TP16.2: vw bleibt bypass (harter Constraint) — Haertung ohne Client-Bruch

User-Constraint 2026-08-14: vw wird NICHT WARP-/Access-geschuetzt, dauerhaft.
Begruendung ist technisch, nicht Bequemlichkeit — die Bitwarden-Clients koennen
den interaktiven Access-Login nicht (dasselbe Muster wie der 400er der
HA-Companion-App). Ein Passwortmanager hinter einem Client, den man im Notfall
nicht installieren kann, ist ein Aussperr-Risiko gegen den eigenen Schluesselbund.
Die TP16-Schritt-5-Absicht "vw von bypass auf geschuetzt heben" ist gestrichen.

Neu: TP16.2 — Haertung aller bypass-Dienste (vw, hass, gitea) in Schichten:
- Schicht 0 (vorhanden): keine offenen Ports, alles ueber CF-Tunnel.
- Schicht 1: Access nur auf /admin* als eigene, spezifischere Application —
  CF wertet die spezifischste App zuerst. Das Admin-Panel wird nur per Browser
  bedient, die Client-Pfade (/api, /identity) bleiben bypass. Kein Client bricht.
- Schicht 2: App-eigene Limits (Vaultwarden LOGIN_RATELIMIT_* sind default an),
  Signups aus, 2FA erzwingen; HA ip_ban_enabled.
- Schicht 3: CF WAF/Rate-Limiting gezielt auf die Login-Endpunkte.
- Schicht 4: CrowdSec/fail2ban mit CF-Bouncer — Bans an der Edge, alle Dienste.

Knackpunkt und Schritt 1: hinter dem Tunnel sieht die App nur die IP des
cloudflared-Containers. Jede IP-Sperre bannt sonst den Tunnel statt den
Angreifer = Selbstaussperrung. Genau dieser Defekt ist schon offen (HA
trusted_proxies fehlen .20.10/.20.167) — X-Forwarded-For/CF-Connecting-IP
sauber durchreichen ist Voraussetzung fuer Schicht 2-4.

Nebeneffekt: TP23s Managed-Networks-Weg ist entlastet — vw verlangt nie
Device-Identity, "WARP zuhause aus" kollidiert nicht mehr mit dem Access-Strang.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-14 16:32:42 +02:00
parent 4443155627
commit 3113218212

View File

@@ -419,7 +419,7 @@ FT kaschierte das bisher als „Roaming" statt „schwache Abdeckung".
- Abh.: TP14 ✅ (IP-Migration). Verzahnt: **TP20** (Platform-DB), **TP21** (Nautobot GC), **TP2.1** (sw2-Standalone-Recovery).
### TP16 — CF-Tunnel: Round-Robin killen + reziprokes HA ▸ ✅ KERN UMGESETZT (2026-07-10) — `docs/cf-tunnel-mapping.md §10`, #1033
> **✅ Umgesetzt (2026-07-10, eigene Session):** reziprokes **3-Tunnel-HA** live (bf-nas `70d6a4cf` / bf-pve `f7fdf3a6` / bf-mm `7a322261`), 6 Connectoren (2/Host, je Fremdhost), 19 FQDNs Loop-Smoke **0×530**, HA per Host-Ausfall-Sim bewiesen. Round-Robin-#1033 **strukturell weg**. As-Built = `docs/cf-tunnel-mapping.md §10`. **Offen: Schritt 5 Access-Strang (`vw` bypass→geschützt via WARP, `hass`/`ha-mcp` 400/403 → iPhone-WARP-Enrollment) = user-gated; `gateway-dw` (WG→404) klären.**
> **✅ Umgesetzt (2026-07-10, eigene Session):** reziprokes **3-Tunnel-HA** live (bf-nas `70d6a4cf` / bf-pve `f7fdf3a6` / bf-mm `7a322261`), 6 Connectoren (2/Host, je Fremdhost), 19 FQDNs Loop-Smoke **0×530**, HA per Host-Ausfall-Sim bewiesen. Round-Robin-#1033 **strukturell weg**. As-Built = `docs/cf-tunnel-mapping.md §10`. **Schritt 5 Access-Strang: ~~`vw` bypass→geschützt via WARP~~ — 🔴 GESTRICHEN (User-Constraint 2026-08-14, s. TP16.2). Verbleibend offen: `hass`/`ha-mcp` 400/403; `gateway-dw` (WG→404) klären.**
- **Symptom (User):** FQDNs über CF werden **sporadisch / „sehr unsicher"** aufgelöst = #1033-Muster zurück („jeden 3. Schuss eine Niete"). User hat alle 3 cloudflared-Images + Container aktualisiert/neu gestartet.
- **✅ Root-Cause endgültig (User-Diagnose bestätigt): macvlan/ipvlan-Host-Isolation.** Ein cloudflared-Connector ist **blind für macvlan/ipvlan-Container auf seinem EIGENEN Host** (Linux-Kernel-Regel), erreicht aber Fremdhost-L2 + co-lokierte Bridge-Container. Mehrere Connectoren auf EINEM Tunnel = geteilter Ingress + CF-**Round-Robin** → jede Origin, die auf dem Host *eines* Connectors liegt, fällt bei ~**1/N** aus. **Strukturell**, nicht durch „Origins fixen" heilbar. Bsp: `omada .20.175`/`pve-mcp .20.173`/`gitea .20.157`/`grafana .20.109` = NAS-macvlan → vom NAS-Connector NICHT erreichbar.
- **Invariante:** innerhalb EINES Tunnels ist **kein Route→Connector-Pinning** möglich (alle Connectoren teilen Ingress, CF round-robined). „Ausgewählte Routen für ausgewählte Connectoren" = **getrennte Tunnel**.
@@ -433,7 +433,7 @@ FT kaschierte das bisher als „Roaming" statt „schwache Abdeckung".
3 Tunnel, jeder Host fährt 2 cloudflared → Host-Ausfall ⇒ jeder Tunnel ≥1 Connector = **voll HA**. Voraussetzung: jede Origin L2-erreichbar.
- **Ist-Inventory (live 2026-07-10, s. `cf-tunnel-mapping.md §9`):** Ingress v119, 24 Hostnames, 2 live Connectoren. **DOWN/stale:** `pbs .20.135`, `nginx-bf .41.123` (noch VLAN1!), `hermes`+`hermes-geli .20.167`. **Zu klären (Host/Netz):** `vw .20.127`/`ccu .20.232`/`iobroker .20.107`/`z2m25 .20.106` — ggf. `vw`/`ccu` auf VLAN20-macvlan heben. `gateway-dw` (192.168.178.1) = WG-Sonderfall.
- **CF-Access-Strang (verzahnt, s. TP11 Track-B):** `hass`-**400 in der HA-iPhone-App = CF-Access davor** (Companion-App kann Access-Login nicht) → Fix **ohne Passthrough**: iPhone in **WARP** enrollen (Device-Identity erfüllt Access; „Warp Login App" existiert bereits `allow:christoph`). ⚠️ **`vw` = aktuell `bypass` (öffentlich!)** → von bypass auf geschützt heben. „Passthrough-Hosts sind die kritischen" (User).
- **CF-Access-Strang (verzahnt, s. TP11 Track-B):** `hass`-**400 in der HA-iPhone-App = CF-Access davor** (Companion-App kann Access-Login nicht) → Fix **ohne Passthrough**: iPhone in **WARP** enrollen (Device-Identity erfüllt Access; „Warp Login App" existiert bereits `allow:christoph`). ~~⚠️ **`vw` = aktuell `bypass` (öffentlich!)** → von bypass auf geschützt heben.~~ 🔴 **Überholt (2026-08-14): `vw` BLEIBT bypass — harter User-Constraint, Härtung stattdessen über TP16.2.** „Passthrough-Hosts sind die kritischen" (User).
- **Umsetzungs-Reihenfolge (für die eigene Session):** (1) **Reachability-Matrix je Host** (pve/NAS/macmini → jede Origin, read-only) BEVOR gruppiert wird; (2) **Interim-Sofortfix:** bf-Tunnel auf **pve-only** (pve erreicht alles außer gateway-dw) → 0×1033, reversibel; (3) reziprokes 3-Tunnel-HA bauen (CNAMEs re-pointen, 6 Connectoren, Token je Tunnel; NAS/macmini-Alt-Token entfernen); (4) tote Origins bereinigen; (5) Access-Strang (WARP + vw); (6) Loop-Gegentest.
- Abh.: TP14.1/14.2 ✅. Verwandt: **TP11** (CF-Tunnel-Track-B/C + Access), #1033. SSoT: `docs/cf-tunnel-mapping.md`. Memory `project_cf_tunnel_1033`.
- ✅ **Incident 2026-07-16 (User unterwegs, WARP „spinnt", keine BF-IPs mehr) ▸ Public-FQDN-Teil gefixt:** macmini-Connectoren (`cloudflared-bfnas`/`-bfpve`) flappten live unter QUIC/UDP (Docker-Desktop-Bridge-NAT) → `bf-nas`/`bf-pve` von 2 auf 1 Connector degradiert (HA faktisch weg, nicht down). Fix: beide auf `TUNNEL_TRANSPORT_PROTOCOL=http2` umgestellt (rollend, 0 Downtime), wieder voll HA. Konvention: macmini-Connectoren künftig immer `http2`. **ICMP-Befund (getrennt, strukturell):** TCP über die WARP-Route ging überall, ICMP nicht (fm 36 %/bf 100 %/dw 100 % Loss) — cloudflared ist QUIC-Proxy, kein WireGuard. **Kurz als „bf-pve-Route wegen USV" notiert (Commit `1c1a676`) → REVIDIERT** (Begründung invertiert: bf-pve-Connectoren laufen auf NAS+macmini, nicht pve). Details: `docs/cf-tunnel-mapping.md §13`. **→ Richtungswechsel für Private Access = TP16.1.**
@@ -448,6 +448,20 @@ FT kaschierte das bisher als „Roaming" statt „schwache Abdeckung".
- ✅ **Recherche-Härtung 2026-07-17 (Primärquellen animmouse + offizielle CF-Docs + OpenAPI-Spec, alles verifiziert, gilt unabhängig vom Zielgerät):** (1) Produkt heißt seit 2026-04-14 offiziell **Cloudflare Mesh** (API-Pfade bleiben `warp_connector`, im Spec bestätigt inkl. Token- und sogar HA-Endpoints); (2) ICMP-Proxy ist **bereits AN** (User-Korrektur: fm-Ping `10.101.0.0/24` beweist es — kein To-Do; mein „fehlt" war ein Fehlschluss aus dem API-Spec, das Flag ist Dashboard-only); (3) Split-Tunnel-Exclude auf **beiden** Device-Profilen (Default + Mesh); (4) **vnet-Gotcha** beim Route-Umzug („virtual networks only for cloudflared") → Weg A PATCH, Weg B DELETE+POST dokumentiert; (5) **v4-only-Entscheid** (Mesh-IPv6-site-to-site laut Guide broken, NAT66-Gefrickel nicht nötig); (6) keepalive 1m statt 25s ok. Alles in `docs/tp16.1-warp-mesh-native-crs326.md` §2/§4 eingearbeitet (Config-Block dort als Platzhalter markiert, IP/Interface TBD).
- Abh.: TP16 ✅ (Public-Teil), TP10 ✅ (WG-Grundmuster, jetzt als Vorbild statt Direktziel), **TP15** (CRS326-Bring-up), **TP21** (Nautobot-Adoption des CRS326, Voraussetzung fürs Scharfschalten). SSoT: `docs/tp16.1-warp-mesh-native-crs326.md`, `docs/cf-tunnel-mapping.md §14`.
### TP16.2 — Härtung der öffentlich erreichbaren Dienste (bypass-Strang) ▸ 📋 KONZEPT (2026-08-14), Umsetzung offen
- 🔴 **HARTER CONSTRAINT (User 2026-08-14): `vw` wird NICHT WARP-/Access-geschützt.** Gilt dauerhaft, nicht „vorerst". **Begründung (technisch belastbar, nicht Bequemlichkeit):** die Bitwarden-Clients (Browser-Extension, Mobile, Desktop) können den **interaktiven Access-Login nicht durchführen** — dasselbe Muster, das die HA-Companion-App auf `400` laufen lässt. Ein Passwortmanager hinter einem Client, den man im Notfall (fremdes Gerät, Neuinstallation, Handyverlust) nicht installieren kann, ist ein **Aussperr-Risiko gegen den eigenen Schlüsselbund** — und damit gefährlicher als das, wovor die Maßnahme schützen soll. **Die frühere TP16-Schritt-5-Absicht „vw von bypass auf geschützt heben" ist damit gestrichen.**
- **Ziel stattdessen: Schutz erhöhen, ohne Clients zu brechen** — gilt für **alle** bypass-Dienste (`vw`, `hass`, `gitea`).
- ✅ **Schicht 0 — bereits vorhanden, nicht unterschätzen:** keine offenen Ports, **alles ausschließlich über CF-Tunnel** (3-Tunnel-HA, TP16), TLS terminiert an der Edge, DDoS-Schutz. Der Origin ist nicht direkt erreichbar. Das ist bereits mehr als bei den meisten Selfhostern.
- ✅ **Schicht 1 — chirurgisch: Access nur auf die Pfade, die kein Client anfasst.** CF Access wertet **die spezifischere Application zuerst** → man kann eine **zweite Access-App auf `vw.emsenhuber.net/admin*`** legen (echte Policy) und den Host im Übrigen auf bypass lassen. **Das Admin-Panel wird ausschließlich per Browser bedient — dort funktioniert der Access-Login einwandfrei**, während `/api`, `/identity` und `/notifications` (die Client-Pfade) unberührt bleiben. Kein Client bricht, das wertvollste Ziel ist weg.
- Alternativ noch härter: **Admin-Panel ganz aus** (`ADMIN_TOKEN` leer lassen) und nur bei Bedarf temporär aktivieren.
- Analog für **`gitea`**: `/admin*` + Registrierung path-scoped schützen (Git-über-HTTPS mit Token bleibt offen).
- ✅ **Schicht 2 — App-eigene Bremsen (kostenlos, sofort):** Vaultwarden hat Rate-Limits **per Default an** (`LOGIN_RATELIMIT_SECONDS=60`, `LOGIN_RATELIMIT_MAX_BURST=10`, dazu `ADMIN_RATELIMIT_*`) → Werte prüfen/verschärfen; `SIGNUPS_ALLOWED=false`, `INVITATIONS_ALLOWED=false`, `SHOW_PASSWORD_HINT=false`, **2FA erzwingen**. HA hat `ip_ban_enabled` + `login_attempts_threshold`. Gitea: Registrierung aus.
- ✅ **Schicht 3 — Edge-Regeln (CF), wirkt für alle Dienste gemeinsam:** WAF-Custom-Rules + **Rate Limiting gezielt auf die Login-Endpunkte** (`/identity/connect/token` bei vw, `/auth/login` bei HA, `/user/login` bei Gitea); optional Geo-/ASN-Filter. ⚠️ **Free-Plan-Kontingente vorher im Dashboard prüfen** (nicht belegt).
- ✅ **Schicht 4 — ein Mechanismus für alle: CrowdSec (oder fail2ban) mit Cloudflare-Bouncer.** Bans landen dann **an der Edge** statt erst am Origin. Vaultwarden hat ein offizielles Fail2Ban-Setup-Wiki (Log-Muster für Login **und** Admin-Panel).
- 🔴 **Voraussetzung für Schicht 2–4, und der eigentliche Knackpunkt: die echte Client-IP muss am Origin ankommen.** Hinter dem CF-Tunnel sieht die Anwendung sonst **nur die IP des cloudflared-Containers** → jede IP-Sperre bannt den Tunnel statt den Angreifer = **Selbstaussperrung aller Nutzer**, und Rate-Limits greifen ins Leere. **Genau dieser Defekt ist bereits offen dokumentiert:** HAs `trusted_proxies` fehlen `.20.10`/`.20.167` (TP16, `hass`-400-Strang). ➡️ **`X-Forwarded-For`/`CF-Connecting-IP` sauber durchreichen ist Schritt 1 dieses TPs**, alles andere baut darauf auf.
- **Reihenfolge:** (1) Client-IP-Weitergabe fixen (inkl. HA `trusted_proxies`) → (2) `/admin`-Pfade path-scoped schützen → (3) App-Limits + 2FA → (4) Edge-Rules → (5) CrowdSec/fail2ban mit CF-Bouncer.
- **Abh.:** TP16 ✅ (Tunnel-HA). Verwandt: **TP20.1** (vw wandert auf Platform-Postgres — DB-HA ≠ Access, getrennt halten), **TP23** (dessen WARP-Managed-Network-Idee ist durch diesen Constraint **entlastet**: `vw` verlangt keine Device-Identity, also kollidiert „WARP zuhause aus" nicht mehr mit dem Access-Strang).
### TP17 — Shelly-Übersiedelung VLAN1 → VLAN30 (IOT) + `shelly-mcp` ▸ ✅ **KOMPLETT (User-Bestätigt 2026-08-13): alle Shellys auf VLAN30** — Geräte-PW (TP17.2) weiterhin bewusst zurückgestellt — `mcp/shelly/`, Runbook `docs/tp17-shelly-go-runbook.md`
- ✅ **Abschluss 2026-08-13 (User-Bestätigt):** auch die zuletzt offenen saisonalen Shellys (s1/s2/s3/s12) sind inzwischen umgeklemmt — **alle Shellys auf `dirtyvader-iot`/VLAN30**, kein VLAN1-Shelly-Rest mehr. Migration-Teil von TP17 damit vollständig abgeschlossen.
- ✅ **GO durchgezogen 2026-07-13 (16 Shellys VLAN1→VLAN30, 0 Fehler):** Pilot s26 + Welle A (s4–s9) + Welle B (s10/11/13/15/17/19/20/21/25) → alle auf `dirtyvader-iot`/`10.40.30.<octet>` verifiziert (SSID+IP+rssi). Mit den 6 Vorab-Migrierten (s14/16/18/22/23/24) = **22/26 auf VLAN30**; VLAN1-Sweep `.180-250` = **0 Shellys**. Restliche 4 saisonal ausgesteckte (s1/s2/s3/s12) inzwischen ebenfalls migriert (s.o.).
@@ -675,7 +689,7 @@ FT kaschierte das bisher als „Roaming" statt „schwache Abdeckung".
- **Verworfen:** eigene Self-Service-UI bauen · per-Device-DoH via NextDNS/ControlD (Agent-Zwang, bricht `bf.lan`) · Umbrella ($30–45/User/Jahr) · Cloudflare verlassen (wirft TP16/TP16.1 weg) · Adlist auf dem Core.
- **Zuweisung ist nativ möglich:** `/ip/dhcp-server/lease` hat die Property **`dhcp-option`** (verifiziert) → **Option 6 pro Lease**, bei 54 Reservierungen ein Konfigurationsschritt. *(Nebenfund: Leases haben `address-lists` → automatische Aufnahme in eine Firewall-Liste, direkt nützlich für die TP5-JIT-Gruppe.)*
- ✅ **WARP im LAN abschalten — Mechanismus: Cloudflare „Managed Networks".** Der Client sucht bei jedem Netzwechsel einen **selbst gehosteten TLS-Endpunkt**, prüft dessen SHA-256-Fingerprint und zieht ein Device-Profil, das WARP **deaktiviert**. Beacon auf **NAS/pve**, nicht auf den Core (`certs=0`). Beseitigt die ICMP-Falle vom 2026-08-13 (`ref_warp_local_icmp_trap`) an der Wurzel.
- ⚠️ **Side effect, der bewusst entschieden werden muss:** CF-Access-Apps, deren Policy Device-Identity verlangt, brechen zuhause. Aktuell unkritisch (`vw`/`hass` = bypass), **aber der offene TP16-Schritt 5 will `vw` genau auf WARP-geschützt heben** → kollidiert frontal. Auflösung: Access-Policy zusätzlich auf die Heim-IP (`bf4-home-ip` existiert) **oder** WARP dort anlassen.
- ✅ **Kollision aufgelöst (2026-08-14):** die frühere Sorge war, dass TP16-Schritt 5 `vw` auf WARP-geschützt hebt und damit „WARP zuhause aus" bricht. **Der User-Constraint aus TP16.2 streicht genau das** — `vw` bleibt bypass und verlangt nie Device-Identity. **Damit steht der Managed-Networks-Weg frei.** Rest-Risiko nur für Dienste, die künftig doch Device-Identity verlangen sollten → dann Access-Policy zusätzlich auf die Heim-IP (`bf4-home-ip` existiert bereits).
- ✅ **Kein Verlust beim Fremdnetz-Zugriff:** FM/DW laufen über den WG-Hub (TP10), nicht über WARP. Managed Networks schaltet nur *im* Heimnetz ab.
- ⚠️ Free-Plan-Verfügbarkeit des Features **nicht belegt** → im Dashboard gegenprüfen. Holzhammer-Alternative (WARP-Endpunkte per Firewall sperren) **nicht empfohlen**: bricht still, Client probiert Transport-Fallbacks, trifft auch Gäste.
- **Umsetzung in Stufen — Sperre zuletzt:**