Files
management/verfahren/aar/2026-08-01-labnet02-cfgmon.md
T
Thore Cimbal 97fe9e0fa8 verfahren: AAR LABNET-02 -- Nachtrag 3: Reboot-Beweis erbracht
Host-Neustart 2026-08-01 ~21:57 CEST. Tunnel, Bootfix (After=docker.service),
Firewall-Regeln und Split-DNS kamen ohne manuellen Eingriff hoch; Handshake
2 s nach Messbeginn. Bootfix und Persistenz damit im Ernstfall verifiziert.
2026-08-01 12:00:00 +00:00

11 KiB
Raw Blame History

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 Handshake0 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 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 UDMwg 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.