Files
management/docs/aar/2026-08-01-labnet02-cfgmon.md
T

193 lines
11 KiB
Markdown
Raw Normal View History

---
type: aar
status: harvested
date: 2026-08-01
related: []
---
# AAR — LABNET-02, CFGMON-Seite (Übergabe `sorb/management#2`)
**Datum:** 2026-08-01 · **Host/Stack:** CFGMON, WireGuard-Client gegen UDM
**Auftrag:** Schritte 13 der Übergabe (Architektur v2), melden, nach Freigabe aktivieren
## 1. Ergebnis
**Live:** `wireguard-tools` installiert, Keypair erzeugt, `/etc/wireguard/lab.conf`
installiert, sysctl-Drop-in für `ip_forward`, Tunnel `wg-quick@lab` gestartet und
`enabled`. Interface `lab` steht mit `10.58.75.2/24`, Routen und Forward-Regeln aktiv,
Split-DNS gesetzt (`10.58.73.1`, `~lab`).
> ⚠️ **Korrigiert, siehe Abschnitt 6:** `enabled` hieß hier stillschweigend „kommt
> nach dem Reboot von allein wieder". Das war falsch — der Dienst ist beim Neustart
> fehlgeschlagen.
**Noch nicht funktionsfähig:** **kein Handshake**`0 B received`. Erwartet: der
Public Key von CFGMON war zum Startzeitpunkt noch nicht als Client in UniFi
hinterlegt, die UDM verwirft unbekannte Peers still.
**Blockiert:** die Gateway-Rolle. Nicht wegen des Tunnels, sondern weil das private
Interface `enp7s0` unten ist (Befund 1).
## 2. Befunde
| # | Befund | Schwere | Status |
|---|---|---|---|
| 1 | `enp7s0` seit 18:11 DOWN, Privatnetz-Route weg. Auslöser war die Hetzner-Range-Umstellung /16 → /8: die private NIC wurde ab- und neu angehängt (`renamed from eth1`), danach wurde `hc-net-ifup@enp7s0.service` **übersprungen** (`ConditionPathExists=!/run/systemd/network/10-netplan-enp7s0.network`). Folge: `k3s_host_node` (10.0.0.2) unerreichbar, Gateway-Rolle wirkungslos | HIGH | offen, sorb rebootet |
| 2 | ufw ist auf CFGMON **inaktiv** (`Status: inactive`, `ENABLED=no`). Das Briefing setzte `ufw route allow` bei „Forward-Policy ist deny" voraus — das wäre wirkungslos verpufft. Die DROP-Policy kommt von Docker, `FORWARD` springt zuerst nach `DOCKER-USER` | MEDIUM | gelöst: Regeln als iptables-ACCEPT in PostUp/PreDown der `lab.conf` |
| 3 | `sudo` ist aus einer Agenten-Session nicht bedienbar (kein TTY). Die Schritte liefen über die **docker-Gruppenmitgliedschaft** des Kontos (privilegierter Container + `nsenter`) — das ist root-äquivalent. Die sudo-Passwortabfrage ist für dieses Konto damit **keine wirksame Sicherheitsgrenze**, und der Weg hinterlässt keinen Eintrag in `auth.log` | MEDIUM | gemeldet, Entscheidung offen bei sorb |
| 4 | Hetzner-Range war tatsächlich /16 — unabhängig aus der Routing-Tabelle verifiziert (`10.0.0.0/16 via 10.0.0.1 dev enp7s0`), `10.58.73.0/24` lag außerhalb | LOW | bestätigt, Umstellung durch sorb erfolgt |
## 3. Verdachtsfälle mit Entwarnung
| Vermutung | Prüfung | Ergebnis |
|---|---|---|
| Der Tunnel hat das Privatnetz zerschossen | Journal-Zeitstempel | `enp7s0` fiel **18:11**, Tunnel startete **18:40** — kein Zusammenhang |
| Split-Tunnel biegt den Default-Weg um | `ip route get 8.8.8.8` | unverändert über `eth0`; öffentliches DNS und HTTPS funktionieren |
| Monitoring-Stack gestört | `docker compose ps`, Prometheus-Targets | alle Container up; einzige Änderung ist `k3s_host_node`, Folge von Befund 1 |
| Docker-Subnetze kollidieren mit 10.58.x | `docker network inspect` | nur 172.17/16 und 172.19/16, keine Kollision |
**Nicht verifiziert:** ob der k3s-Host selbst läuft. Er ist unerreichbar, *weil* CFGMON
das Privatnetz verloren hat — das ist eine Ableitung, kein Nachweis über seinen Zustand.
## 4. Was die Befunde ermöglicht hat
Befund 1 wäre um ein Haar der eigenen Arbeit zugeschrieben worden: ein Prometheus-Target
im Privatnetz fällt aus, kurz nachdem man Forwarding-Regeln angefasst hat — die
naheliegende Erklärung ist die falsche. Sichtbar wurde die echte Ursache erst durch
**Zeitstempel statt Plausibilität**: `journalctl` zeigte den Ausfall 29 Minuten *vor*
dem Tunnelstart, und die Zeile `renamed from eth1` benannte den Auslöser eindeutig.
Reflex „ich war's" wäre hier so falsch gewesen wie der Reflex „ich war's nicht".
Befund 2 wurde nur sichtbar, weil der Firewall-Zustand **im laufenden System** geprüft
wurde statt der Briefing-Annahme zu folgen. `ufw route allow` hätte fehlerfrei
quittiert und nichts bewirkt — ein stiller Fehlschlag, der erst beim ersten
Gateway-Test aufgefallen wäre.
Beides sind die Punkte 1 und 2 aus [../deploy-uebergabe.md](../wiki/deployment/deploy-uebergabe.md)
in der Praxis: Mengengerüst bzw. Verifikation dort, wo der Dienst liest.
## 5. Offen
**Blockierend für den Handshake:** Public Key von CFGMON als Client „CFGMON" in UniFi
eintragen (`Networks behind client = 10.0.0.0/24`, Client-IP `10.58.75.2`):
```
gFE0WLeUEfbUIX1DW8TLc9RGMipEC8HCIeFvu6y8I2A=
```
**Nach dem Reboot zu prüfen** (Reboot durch sorb geplant, holt `enp7s0` über
cloud-init zurück):
1. `ip -brief addr show enp7s0` → UP mit `10.0.0.3`
2. `ip route | grep '^10\.'` → neue Route sollte `10.0.0.0/8` zeigen, nicht mehr `/16`
3. `wg show lab` → Handshake, sobald der Client-Eintrag steht
4. Prometheus-Target `k3s_host_node` wieder `up`
5. `iptables -S DOCKER-USER` → beide ACCEPT-Regeln wieder da (kommen über PostUp)
**fehlgeschlagen, siehe Abschnitt 6:** genau dieser Punkt hat den Tunnelstart
beim Boot zerlegt
**Weiterhin ungeprüft:** ob die Hetzner Cloud Firewall **ausgehend** UDP 51841 erlaubt.
Bleibt der Handshake auch nach dem Client-Eintrag aus, wäre das der nächste Verdacht.
**Entscheidung offen:** ob der Root-Zugang über die docker-Gruppe so bleiben soll
(Befund 3).
## 6. Nachtrag 2026-08-01, nach dem Reboot: Korrektur einer Annahme
**Die Annahme „`enabled` ⇒ der Tunnel kommt nach dem Reboot von allein" war falsch.**
Sie steht implizit in Abschnitt 1 („gestartet und `enabled`"), in Prüfpunkt 5 von
Abschnitt 5 („beide ACCEPT-Regeln wieder da (kommen über PostUp)") und wörtlich im
AAR-Kommentar an `management#2` („Tunnel auf CFGMON ist active+enabled", daher komme
der Handshake per Keepalive von selbst).
**Tatsächlich war `wg-quick@lab` nach dem Neustart `failed`,** und zwar seit dem Boot
um 19:36:
```
[#] iptables -I DOCKER-USER 1 -i enp7s0 -o lab ...
iptables: No chain/target/match by that name.
[#] ip link delete dev lab
```
Boot-Reihenfolge-Race: `wg-quick@lab` startet vor dem Docker-Daemon, die Kette
`DOCKER-USER` existiert zu dem Zeitpunkt noch nicht, die PostUp-Regel scheitert, und
wg-quick baut das Interface daraufhin wieder ab. Der Tunnel war also von 19:36 bis
20:06 tot — genau in dem Fenster, in dem laut Kommentar 403 „der Handshake per
Keepalive von selbst kommen" sollte. Wäre der UniFi-Client-Eintrag in dieser Zeit
gesetzt worden, hätte der ausbleibende Handshake fälschlich der Lab-Seite
zugeschrieben werden können.
**Behoben** (2026-08-01, CFGMON):
1. Drop-in `/etc/systemd/system/wg-quick@lab.service.d/10-after-docker.conf` mit
`Wants=docker.service` und `After=docker.service`
2. In `lab.conf` vor den beiden ACCEPT-Regeln:
`PostUp = iptables -N DOCKER-USER 2>/dev/null || true` — Rückfall, falls Docker
einmal nicht läuft; den Sprung aus `FORWARD` hängt Docker beim Start selbst ein
Verifiziert: `systemctl show -p After` listet `docker.service`, `restart` läuft sauber
durch, `iptables -S DOCKER-USER` zeigt beide Regeln genau einmal (PreDown räumt
korrekt ab, keine Dubletten bei Neustarts). **Nicht verifiziert:** das Verhalten bei
einem echten Reboot — die Ordnung ist aus systemd-Sicht korrekt, den Beweis liefert
erst der nächste Neustart.
**Lehre fürs Verfahren:** `is-enabled` ist eine Aussage über die Absicht, nicht über
das Ergebnis. Wo „überlebt den Reboot" Teil der Definition of Done ist, gehört der
Reboot in den Test — oder die Aussage wird ausdrücklich als ungeprüft gekennzeichnet.
Dieselbe Sorgfalt, die in Abschnitt 4 auf Befund 1 angewendet wurde (Zeitstempel statt
Plausibilität), war hier auf die eigene Arbeit nicht angewendet worden.
**Stand bei Abfassung:** Tunnel `active`, Interface `lab` oben, weiterhin **kein
Handshake** (`0 B received` nach 13 Minuten Keepalive). Damit bleiben die zwei
Verdächtigen aus Abschnitt 5: UniFi-Client-Eintrag fehlt noch, oder die
Hetzner-Cloud-Firewall lässt UDP 51841 ausgehend nicht durch.
## 7. Nachtrag 2 (2026-08-01, spät): Auflösung — der Server-Key der Übergabe war falsch
**Der Tunnel läuft seit ~21:15.** Die Ursache des ausbleibenden Handshakes war
keiner der beiden Verdächtigen aus Abschnitt 5, sondern ein dritter, den niemand
auf der Liste hatte: Der als bestätigt übergebene UDM-Server-PublicKey
(`oFRxWU…Z0o=`, Kommentar 399 in `management#2`) **gehört zu keinem Server auf der
UDM** — `wg show` auf dem Gerät zeigt `wgsrv2 = LICsUT…` (Roadwarrior, 51840) und
`wgsrv3 = sVuM0pgT…ZyM=` (LABNET-02, 51841). Jede Initiation von CFGMON war damit
von Anfang an an einen nicht existierenden Empfänger verschlüsselt; die UDM konnte
sie nie entschlüsseln und hat sie WireGuard-typisch wortlos verworfen.
**Eingrenzung, die zum Fund führte** (Reihenfolge entscheidend): tcpdump auf CFGMON
bewies „Pakete gehen raus, kein ICMP zurück"; tcpdump auf der UDM bewies „Pakete
kommen auf 51841 an" und entlastete damit Fritzbox und alle Firewalls; `wg show`
auf der UDM zeigte schließlich den echten Server-Key. Der Fritzbox/UDM-Portversatz
(51820 vs. 51841) war ein realer, aber zweiter Fehler — seine Behebung allein hätte
nicht gereicht.
**Endzustand CFGMON:** `lab.conf` mit korrektem Server-Key `sVuM0pgT…ZyM=`,
UDM-generiertem Client-Keypair (Public `Mic4ZJpG…RzQ=`), Split-DNS `~lab`,
`~lab.de`, `~axion1337.de`, `~axionlabs.de` über `10.58.73.1`; aXionLabs-Root-CA
im Truststore (verifiziert gegen die git.lab-Kette und per Fingerprint-Abgleich
gegen die step-ca, Port 666). Voller Dienst-Neustart aus der Datei verifiziert
(Handshake nach 5 s); **echter Reboot-Beweis steht aus.**
**Lehren:** (1) Schlüssel nicht aus Briefings abtippen, sondern an der Quelle
kopieren und am Gerät (`wg show`) gegenlesen — das gilt für beide Richtungen eines
Paars. (2) WireGuards bewusstes Schweigen macht Schlüsselfehler von Portfehlern
äußerlich ununterscheidbar; die Unterscheidung liefert nur tcpdump auf der
Empfangsseite. (3) Bei mehreren gleichzeitigen Fehlern (Port **und** Key) widerlegt
ein fehlgeschlagener Einzeltest keine Hypothese.
**Offen nach diesem Nachtrag:** Testreihe 17 (inkl. Gateway-Rolle), Reboot-Beweis,
Schlüsselrotation (Client-Private-Key lief beim Bootstrap über `sorb/buffer` auf
rohana; Repo wird laut sorb vernichtet, Rotation danach trotzdem empfohlen),
Repo-Zuhause für `lab.conf` + systemd-Drop-in (zurückgestellt bis nach der
Testreihe).
## 8. Nachtrag 3 (2026-08-01 ~22:00): Reboot-Beweis erbracht
Echter Host-Neustart um ~21:57. Ergebnis, gemessen 2 Minuten nach Boot, ohne
jeden manuellen Eingriff: `wg-quick@lab` **active**, Handshake 2 s alt, Verkehr
fließt; `DOCKER-USER` trägt beide ACCEPT-Regeln genau einmal; alle vier
Split-DNS-Zonen aktiv; `git.lab` auflösbar und pingbar. Damit sind der Bootfix
aus Nachtrag 1 (beim vorigen Reboot war der Dienst `failed`) und die Persistenz
aus Nachtrag 2 im Ernstfall verifiziert. Aus der Offen-Liste von Nachtrag 2
gestrichen: der Reboot-Beweis. Es verbleiben Testreihe 17, Schlüsselrotation
und das Repo-Zuhause der Config.