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>
9.9 KiB
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:
- Die Mesh-Route steht. Auf dem Core: die vnet-Route
10.40.0.0/16zeigt aufbf-core-mesh(TP16.1 §4.4, „Weg A"). Ohne sie ist Mesh-Zugriff auf10.40.20.30gar nicht möglich. - 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 - ⚠️ 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:
- Ist-Config sichern (das ist der Rollback):
GET /accounts/{account_id}/cfd_tunnel/{tunnel_id}/configurations→ JSON wegschreiben, mit Datum. - Aus dem
ingress-Array dienautobot-Zeile entfernen. ⚠️ Die abschließende Catch-all-Regel (service: http_status:404ohnehostname) muss die letzte bleiben — sonst greift der Ingress für alle übrigen Hostnames nicht mehr. - Zurückschreiben:
PUTderselben Route mit dem gekürzten Array. - Gegenprobe am Gerät, nicht am Statuscode: ein
GETder 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,n8nbleiben öffentlich — harte Kriterien: Bitwarden-Clients (TP16.2-Constraint), die HA-Companion-App (das 400-Muster), eingehende Webhooks von Dritten.giteaist 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:
- 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.
- 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.