# 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.**