Files
bf-infra/docs/tp16.3-nautobot-mesh-only-runbook.md
Christoph Emsenhuber ec8051508e TP16.3: nautobot aus dem CF-Ingress geschnitten, Probe laeuft
Runbook ausgefuehrt. Vorbedingungen alle erfuellt, Testclient hing im
Hotspot-Netz 172.20.10.13 mit aktivem WARP -- also nicht im BF-LAN, der
einzige Aufbau der fuer Vorbedingung 2 etwas beweist.

Schnitt: nautobot.emsenhuber.net aus bf-nas (8 -> 7 Regeln), Catch-all
bleibt letzte. Rollback-Sicherung in docs/cf-backup/. Gegenprobe durch
Zuruecklesen der Config, nicht am Statuscode.

Abnahme vollstaendig, inkl. des uebersehenen Punktes: Golden Config lief
durch (Backup -> Intended -> Compliance, 104/104, 0 Drifts). Die uebrigen
fuenf bf-nas-Hostnames unveraendert.

Befund, der die Abnahmetabelle des Runbooks korrigiert: der oeffentliche
FQDN taugt nicht als Test. Er liefert vor UND nach dem Schnitt 302, weil
der von Cloudflare Access kommt, nicht vom Origin -- Access greift vor
dem Tunnel (JWT: auth_status NONE bei is_warp true). Damit auch eine
ehrlichere Erwartung: nautobot war nie ohne Access-Login oeffentlich
erreichbar, der Schnitt entfernt die zweite Tuer, nicht die erste.

Paragraph 7 des Runbooks ist ueberholt -- die HA-Degradierung ist am
selben Tag repariert, der Fall steht auf dem verbliebenen Argument.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-24 10:33:43 +02:00

9.9 KiB
Raw Blame History

TP16.3 — Probe: nautobot aus dem CF-Ingress nehmen (mesh-only)

Stand 2026-08-19 · vorbereitet, nicht ausgeführt. Die Recherche zu TP16.3 ist seit 2026-08-17 durch; offen war nur die Umsetzung. Dieses Runbook macht daraus einen ausführbaren, in einer Minute zurücknehmbaren Schnitt.


1. Worum es geht (in drei Sätzen)

Der private Datenpfad läuft seit TP16.1 über natives WireGuard auf dem Core (cf-mesh), nicht über Container — belegt, nicht vermutet: im TP5-Log-Lauf standen 137 Zeilen in:cf-mesh. Für Dienste, die niemand ohne WARP im Browser aufrufen muss, ist cloudflared damit überflüssiger Aufwand: eine Ingress-Zeile, ein Connector-Paar, eine HA-Frage. Diese Probe nimmt einen solchen Dienst heraus und schaut eine Woche zu.

Warum ausgerechnet nautobot

Kriterium nautobot
Wer nutzt es nur Christoph — kein Fremdgerät, kein Gast
Braucht es einen Client ohne Access-Login? nein (das ist das TP16.2-Kriterium, an dem vw hängt)
Wie oft schon per Mesh angefasst 62× im TP5-Log — der Spitzenreiter
Was kostet ein Fehlschlag nichts Produktives; im Zweifel greift man per IP zu

2. 🔴 Die Verwechslungsfalle, die den ganzen TP kippen kann

Mesh-Hostname-Routes sind Egress, nicht Publishing. Cloudflare kennt seit 2026-07-02 auch Hostname-Routes auf dem Mesh — die klingen so, als könnten sie den Ingress ersetzen. Sie können es nicht: sie leiten ausgehenden Verkehr zu diesem Hostname über den Node und egressen mit dessen öffentlicher IP. Sie veröffentlichen nichts.

Wer das verwechselt, baut den öffentlichen Strang ab und wundert sich, warum von außen nichts mehr geht. → Diese Probe ersetzt nichts. Sie entfernt einen Dienst, der öffentlich gar nicht gebraucht wird.


3. Vorbedingung — VOR dem Schnitt prüfen (read-only)

Alle drei Punkte müssen erfüllt sein, sonst wird nicht geschnitten:

  1. Die Mesh-Route steht. Auf dem Core: die vnet-Route 10.40.0.0/16 zeigt auf bf-core-mesh (TP16.1 §4.4, „Weg A"). Ohne sie ist Mesh-Zugriff auf 10.40.20.30 gar nicht möglich.
  2. Der Dienst antwortet über die private IP, mit aktivem WARP — von einem Client, der nicht im BF-LAN steht (das ist der einzige Test, der etwas beweist; im LAN geht es ohnehin):
    http://10.40.20.30:8080
    
  3. ⚠️ ICMP nicht als Beweis nehmen, aber auch nicht als Gegenbeweis. Der Mesh kann ICMP (das war der Gewinn von TP16.1). Wenn Ping scheitert, TCP aber geht, ist zuerst zu prüfen, ob lokal noch ein WARP-Client läuft — s. Memory ref_warp_local_icmp_trap. Umgekehrt ist ein erfolgreicher Ping kein Beleg, dass der HTTP-Dienst erreichbar ist.

4. Der Schnitt

Was: die nautobot-Zeile aus der Ingress-Config des Tunnels bf-nas entfernen. Die DNS-CNAME-Zeile bleibt zunächst stehen (Rollback bleibt so eine reine Ingress-Operation).

Womit: die Cloudflare-API mit CF_API_TOKEN.

🔴 Nicht über den Cloudflare-MCP. Der ist strikt read-only — Writes gehen ausschließlich über die API mit dem Token (Memory ref_cf_mcp_readonly_token_writes). Das Token ist account-owned, nutzt also einen anderen verify-Endpoint als ein User-Token, und läuft am 2027-01-09 ab.

Wo die Werte stehen: mcp/cloudflare/.env (chmod 600, gitignored) — CF_API_TOKEN, CF_ACCOUNT_ID, CF_BF_TUNNEL_ID.

Ablauf:

  1. Ist-Config sichern (das ist der Rollback): GET /accounts/{account_id}/cfd_tunnel/{tunnel_id}/configurations → JSON wegschreiben, mit Datum.
  2. Aus dem ingress-Array die nautobot-Zeile entfernen. ⚠️ Die abschließende Catch-all-Regel (service: http_status:404 ohne hostname) muss die letzte bleiben — sonst greift der Ingress für alle übrigen Hostnames nicht mehr.
  3. Zurückschreiben: PUT derselben Route mit dem gekürzten Array.
  4. Gegenprobe am Gerät, nicht am Statuscode: ein GET der Config liest zurück, was wirklich steht. (Dieselbe Regel wie in TP22/TP23: ein „success" der API ist kein Wirksamkeitsnachweis.)

5. Abnahme

Prüfung Erwartung
Öffentlicher FQDN nautobot.… ohne WARP nicht mehr erreichbar (das ist der Zweck)
http://10.40.20.30:8080 mit WARP, von außerhalb des LAN erreichbar
Die übrigen Hostnames auf bf-nas (gitea, grafana, pve-mcp, vw, ds-bf) unverändert erreichbar
Golden-Config-Deploys (Netmiko aus Nautobot) laufen weiter

🔴 Der letzte Punkt ist der, den man übersieht: Nautobot ist nicht nur eine Web-UI, sondern die Deploy-Pipeline. Der Netmiko-Deploy kommt von 10.40.20.31 (nautobot-worker), nicht von .20.30 — das war einer der vier TP5-Funde. Der Schnitt betrifft nur den eingehenden öffentlichen Weg, aber nach dem Schnitt gehört ein Job-Lauf zur Abnahme, nicht nur ein Browser-Aufruf.


6. Betriebsfenster und Rollback

  • Eine Woche fahren, dann entscheiden: bleibt es so, oder kommt es zurück.
  • Rollback = die gesicherte Ingress-Config aus Schritt 1 zurückschreiben. Eine Zeile, eine Minute.
  • Danach ist zu entscheiden, ob weitere Dienste der rechten Spalte folgen (pve, portainer, grafana, pve-mcp, ha-mcp, gitea-mcp, ds-bf, ccu, iobroker, z2m25).

Was in dieser Probe ausdrücklich NICHT entschieden wird

  • vw, hass, n8n bleiben öffentlich — harte Kriterien: Bitwarden-Clients (TP16.2-Constraint), die HA-Companion-App (das 400-Muster), eingehende Webhooks von Dritten.
  • gitea ist offen und wird hier nicht mitentschieden: Git-Clients/CI von außen können keinen interaktiven Access-Login. Braucht eine eigene Prüfung, ob es solche Zugriffe real gibt.

7. Nebeneffekt, der den Fall stärkt

Die TP16-HA-Degradierung (bf-nas und bf-pve haben je nur einen Connector, Befund 2026-08-16) verliert an Gewicht, je weniger Dienste an cloudflared hängen. Das ersetzt die Reparatur nicht — aber es verkleinert, was der SPOF trifft.


8. ▶️ AUSGEFÜHRT 2026-08-24 — der Schnitt sitzt, Probe läuft

Vorbedingungen (§3), alle erfüllt:

Prüfung Ergebnis
vnet-Route 10.40.0.0/16 → bf-core-mesh ✅ vorhanden (CF teamnet/routes)
cf-mesh am Core ✅ R, last-handshake 33 s, 198 MiB rx / 738 MiB tx
http://10.40.20.30:8080 von außerhalb des LAN, WARP aktiv ✅ HTTP 302 in 0,18–0,36 s
ICMP zu 10.40.20.30 ✅ 0 % Loss (kein Beweis, aber es schließt die WARP-Falle aus)

🎯 Der Testclient war zufällig genau der richtige: die Session lief auf einem Host im Hotspot-Netz 172.20.10.13 mit aktivem WARP — also nicht im BF-LAN. Das ist der einzige Aufbau, der für Vorbedingung 2 etwas beweist; aus dem LAN heraus geht es ohnehin.

Der Schnitt: nautobot.emsenhuber.net aus dem Ingress von bf-nas (220c9958-401b-4111-9451-f3db09bba2d5) entfernt, 8 → 7 Regeln, Catch-all weiterhin letzte. Rollback-Sicherung: docs/cf-backup/bf-nas-ingress-20260824-vor-tp16.3.json. Gegenprobe durch Zurücklesen der Config vom Dienst, nicht am Statuscode: nautobot noch drin? False.

Abnahme (§5):

Prüfung Ergebnis
10.40.20.30:8080 mit WARP von außerhalb ✅ 302 in 0,16–0,17 s
gitea / grafana / pve-mcp / vw / ds-bf ✅ je 3 Läufe, unverändert (200/302/302/200/302)
Golden-Config-Pipeline ✅ Backup → Intended → Compliance, 104/104 compliant, 0 Drifts
Öffentlicher FQDN nicht mehr bedient ⚠️ so nicht testbar — s.u.

🔴 Befund: die erste Abnahmezeile aus §5 ist als Test untauglich

https://nautobot.emsenhuber.net/ antwortet vor und nach dem Schnitt mit HTTP 302 — und zwar identisch, weil der 302 nicht vom Origin kommt, sondern von Cloudflare Access: location: https://emsenhuber.cloudflareaccess.com/cdn-cgi/access/login/nautobot.emsenhuber.net. Access greift vor dem Tunnel; der Request erreicht den Ingress gar nicht, solange keine Access-Session besteht. Im mitgelieferten JWT steht "auth_status":"NONE" bei gleichzeitig "is_warp":true — WARP-Identität allein erfüllt die Policy für nautobot nicht, es braucht den interaktiven Login.

⇒ Konsequenzen, beide wichtig:

  1. Der Statuscode des öffentlichen FQDN kann diesen Schnitt weder belegen noch widerlegen. Der gültige Nachweis ist das Zurücklesen der Ingress-Config (oben) — dieselbe Regel wie in TP22/TP23: nicht die Antwort des Frontends zählt, sondern der Zustand am Dienst.
  2. Der öffentliche Weg war schon vorher zu. Nautobot war nie ohne Access-Login erreichbar; der Schnitt entfernt also die zweite von zwei Türen, nicht die erste. Das schmälert den Gewinn nicht (eine Ingress-Zeile und ein Connector-Paar weniger), aber es korrigiert die Erwartung: hier wurde keine offene Tür geschlossen, sondern eine überflüssige entfernt.

📌 Nebenprüfung, die den Schnitt hätte kippen können: nautobot/gc-configplan.py spricht http://10.40.20.30:8080/api — die private IP. Kein Repo-Skript benutzt den öffentlichen Namen (grep über *.py/*.sh/*.yml/*.env: kein Treffer). Die Werkzeugkette hängt also nicht am gekappten Weg. Das gehört vor jeden weiteren Schnitt der rechten Spalte geprüft.

⏳ Offen: das Betriebsfenster

Eine Woche fahren (bis ~2026-08-31), dann entscheiden. Rollback = die gesicherte Config zurückschreiben, eine Minute. Danach steht die Frage, ob pve, portainer, grafana, pve-mcp, ha-mcp, gitea-mcp, ds-bf, ccu, iobroker, z2m25 folgen.

📌 §7 ist überholt

Der dort beschriebene Nebeneffekt („die HA-Degradierung verliert an Gewicht") ist gegenstandslos: TP16 ist am selben Tag repariert — alle drei bf-Tunnel laufen wieder auf 2 Connectoren (cf-tunnel-mapping.md §15). Der Fall für TP16.3 steht damit auf dem verbliebenen Argument, und das ist das eigentliche: weniger bewegliche Teile für Dienste, die öffentlich nicht gebraucht werden.