From 528f133264b5337de673c8b847a5329ccd418503 Mon Sep 17 00:00:00 2001 From: Christoph Emsenhuber Date: Fri, 25 Sep 2026 19:24:13 +0200 Subject: [PATCH] docs: Plan WARP-Egress (nativer Consumer-WARP als WG auf crs326-core) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Routing-Regel statt Mangle: Client-VLANs -> Routing-Tabelle warpout, Router-Infra (wg-hub/cf-mesh/DNS/NTP) bleibt auf Liwest. Nur Plan, nichts ausgeführt. Co-Authored-By: Claude Fable 5 --- docs/warp-egress-native-crs326.md | 132 ++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 docs/warp-egress-native-crs326.md diff --git a/docs/warp-egress-native-crs326.md b/docs/warp-egress-native-crs326.md new file mode 100644 index 0000000..1cc4cba --- /dev/null +++ b/docs/warp-egress-native-crs326.md @@ -0,0 +1,132 @@ +# WARP-Egress — nativer Consumer-WARP (WireGuard) auf dem crs326-core + +> **Status:** PLAN (noch nicht ausgeführt) · 2026-09-25 · TP-Nummer bei Anlage vergeben (nächste freie, Stand TP46). +> **Zweck:** ausgehenden **Client**-Verkehr (alle VLANs) über Cloudflare egressen → **geteilte CF-IP** statt +> blockierter Heim-IP `90.146.33.177`. **Router-eigene Infra bleibt auf Liwest.** +> **Werkzeuge:** **MikroMCP** (`plan_changes`→`apply_plan`) für den Router-Block · **CF-MCP** zum Verifizieren · +> `wgcf` nur für den einen Consumer-WARP-Key · `sshpass` nur für die WG-Zeilen, die MikroMCP nicht kann (TP16.1 §4.3). +> **Muster:** TP16.1 (`docs/tp16.1-warp-mesh-native-crs326.md`) — dort natives WG für **Ingress**, hier für **Egress**. + +--- + +## 1. Kontext / Warum + +- Cannaleo-Origin `164.90.191.7` (DigitalOcean, multi-tenant, ~400 Vhosts) blockt die Heim-IP + `90.146.33.177` hart (leerer `403`, live 2026-09-25). Crawler ist aus, Projekt auf Eis — nur noch privates Surfen/Bestellen. +- Ziel: CF-Egress für **alle Clients/VLANs** (nur die zwei aktiven Nutzer, keine Einschränkung nötig). + +## 2. Entscheidung & Nicht-Ziele + +- **Gewählt:** nativer **Consumer-WARP** als zweites WG-Interface `warpout` auf `crs326-core`. + **Clients über WARP, Router-Infra über Liwest** (Policy-Route via **Routing-Regel** → Routing-Tabelle `warpout`). +- **Verworfen:** WARP-Client als RouterOS-Container (kein `/dev/net/tun`); Mesh-Node als Egress (egressed über + die **eigene** Public-IP = die blockierte); cloudflared (reiner Ingress); **Default-Route-Flip** (würde die + WG-Transporte von `wg-hub`/`cf-mesh`/`warpout` mitreißen → fm/dw kaputt, Hairpin). +- **Nicht-Ziel:** Dedicated Egress (paid) — bewusst „vorerst" geteilte CF-IP. + +## 3. Ist-Stand (live 2026-09-25) + +- `crs326-core` (ROS 7.24.1): WG `cf-mesh` (Ingress `100.96.0.6/32`) + `wg-hub` (FM/DW). Kein Container am Core. +- APs fahren `cfd-min-arm64`-cloudflared-Container (`bf-public`, ~75 MB RAM, Flash nur ~54 MB frei) → **nicht anfassen**. +- Firewall **deny-by-default beide Ketten** (TP5) → Egress braucht explizite `forward`-Regel. +- Routing: Default `0.0.0.0/0 → 90.146.33.1` (vlan100). Nur Routing-Tabelle `main`, keine Mangle-Marks. + +## 4. CF-MCP: Account verifizieren (read-only, Schritt 0) + +Mit `mcp__cloudflare__execute` gegenlesen (bestätigt 2026-09-25): `warp_connector` = nur `bf-core-mesh` +(Mesh, nicht Client) · `egress_cidr_pairs` = `[]` (kein Dedicated Egress). → es gibt **noch keinen** WARP-Client. +> ⚠️ **Grenze des CF-MCP:** die **Consumer-WARP-Registrierung** (PrivateKey + Reserved-IPs) läuft über +> `api.cloudflareclient.com`, NICHT über die Account-API — dafür gibt es **keinen** CF-API-Endpoint. Der CF-MCP +> kann den Account **verifizieren**, aber den Client-Key **nicht** erzeugen. Dafür §5 (wgcf), genau einmal. + +## 5. Einmalig: Consumer-WARP-Key (wgcf, nicht wgcf-connector) + +``` +docker run --rm -v $(pwd):/app/output ghcr.io/animmouse/wgcf register +docker run --rm -v $(pwd):/app/output ghcr.io/animmouse/wgcf generate # → wgcf-profile.conf +``` +- ⚠️ **`wgcf` (Consumer) ≠ `wgcf-connector` (Mesh).** Das Repo hat bisher nur den Connector benutzt. +- `.conf` liefert: **PrivateKey**, `Address = 172.16.0.2/32` (+ v6 → ignorieren, v4-only), Peer-PublicKey + `bmXOC+F1FxEMF9dyiK2H5/1SUtzH0JuVo51h2wPfgyo=` (= gleicher CF-Wellknown-Key wie Mesh), Endpoint + `engage.cloudflareclient.com:2408` → `162.159.192.x`/`.193.x`, MTU 1280. +- **PrivateKey → `~/.secrets`/`mcp/cloudflare/.env`** (`CF_WARP_CLIENT_PRIVKEY`, `chmod 600`, nie in Git). + +## 6. RouterOS — MCP-first + +**Primärpfad:** `mcp__mikromcp__plan_changes` (dryRun, reviewen) → `mcp__mikromcp__apply_plan`. +**Ausnahme (WG):** MikroMCP kann WG-PrivateKey nicht, `endpoint="IP:Port"` wird falsch zerlegt, +`persistent-keepalive` fehlt (TP16.1 §4.3) → diese 4 Zeilen **einmal** via `sshpass -e` (Key aus `.env` +interpoliert, nicht im Literal; Fehlerausgabe `sed`-maskieren — CLAUDE.md-Regel). + +``` +# (a) sshpass — WG-Bring-up (Interface+Key, Peer mit endpoint/keepalive) +/interface wireguard add name=warpout mtu=1280 private-key="" comment="WARP Egress (privat)" +/interface wireguard peers add interface=warpout name=warp-cf-pop \ + public-key="bmXOC+F1FxEMF9dyiK2H5/1SUtzH0JuVo51h2wPfgyo=" \ + endpoint-address=<162.159.192.x|193.x> endpoint-port=2408 \ + allowed-address=0.0.0.0/0 persistent-keepalive=25s +``` + +``` +# (b) MCP plan_changes→apply_plan — alles ohne Secret +/ip address add address=172.16.0.2/32 interface=warpout comment="WARP client (v4)" # manage_ip_address +/routing table add name=warpout fib # manage_routing_table +# lokale Routen in warpout — PFLICHT, sonst läuft VLAN↔VLAN über den Tunnel! +/ip route add dst-address=10.40.10.0/24 gateway=vlan10 routing-table=warpout # manage_route (local) +/ip route add dst-address=10.40.20.0/24 gateway=vlan20 routing-table=warpout # manage_route (local) +# … analog vlan30/vlan40/vlan50/vlan90 (die exakten /24 aus den Connected-Routes übernehmen) +/ip route add dst-address=0.0.0.0/0 gateway=warpout routing-table=warpout # manage_route (Internet via WARP) +# Routing-Regel je Client-VLAN — „die Ausnahme direkt über den WG-Tunnel", kein Mangle +/routing rule add interface=vlan10 action=lookup-only-in-table table=warpout comment="Client -> WARP" # manage_routing_rule +/routing rule add interface=vlan20 action=lookup-only-in-table table=warpout +# … analog vlan30/vlan40/vlan50/vlan90 +/ip firewall nat add chain=srcnat out-interface=warpout action=masquerade comment="WARP egress" # kein NAT-Tool → run_command +/ip firewall filter add chain=forward in-interface=vlan10,vlan20,vlan30,vlan40,vlan50,vlan90 \ + out-interface=warpout action=accept comment="WARP egress fwd" # manage_firewall_rule +``` + +- **Warum Routing-Regel statt Default-Route-Flip:** `main`-Default bleibt `90.146.33.1` → der **WG-Transport** von + `warpout`/`cf-mesh`/`wg-hub` (Endpunkt-IPs) und die Router-eigenen Dienste (DNS-DoH, NTP) laufen weiter über + Liwest. Nur **Client-Ingress** (VLANs) wird umgeleitet → kein Hairpin, **fm/dw und cf-mesh bleiben unberührt**. +- **Scope:** alle Client-VLANs (10/20/30/40/50/90). `vlan99` (Mgmt) + `vlan100` (WAN) bewusst **nicht** umgeleitet. +- **DNS:** bleibt auf dem Core (DoH→CF-Gateway, TP23); nur der Verbindungs-Traffic der Clients geht durch WARP. + +## 7. Nautobot / Golden Config + +1. **Vorher** `/system backup` → `pre-warp-egress-.backup` (TP22-Regel 3). +2. WG-Bring-up direkt (Ausnahme #4-Muster: Privkey nicht GC-deploybar); Route/Mangle/NAT/Firewall/Adresse normal. +3. **Ist-Stand → Nautobot** intended config: Privkey als `<>` (byte-identisch zur `ConfigReplace`-Maske). +4. Compliance-Features ggf. um neue Sektionen erweitern, dann `--refresh-compliance` → grün, keine Drifts. +5. **TP-Anlage** (nach User-Okay): Gitea-Issue + `### TPnn` in `docs/teilprojekte.md`. +6. Diese Datei am Ende auf `✅ AUSGEFÜHRT` + As-Built-Werte setzen. + +## 8. Verifikation + +- Beliebiges Client-Gerät: `curl -s https://cloudflare.com/cdn-cgi/trace` → `warp=on`, `ip=104.28.x.x` + (nicht `90.146.33.177`). +- **Cannaleo-Test:** `curl -s -o /dev/null -w "%{http_code}\n" https://blaueblueten.de/` → **200** (vorher 403). +- **Regression (wichtig!):** `wg-hub`-Peers `fm`/`dw` + `cf-mesh`-Peer `cf-pop` weiterhin `last-handshake < 60s`; + WARP-Zugriff aufs BF-Netz (Mesh) weiter ok. Beweist: Router-Infra blieb auf Liwest, nichts mitgerissen. +- `warpout`-Peer: `last-handshake < 10s`, rx/tx laufen. + +## 9. Rollback + +- Routing-Regeln `disable` (Clients fallen auf `main`-Default = Liwest zurück) ODER `warpout`-Interface `disable`. +- Router-Infra war nie betroffen → fm/dw/cf-mesh unberührt. Reversibel; Backup §7.1. + +## 10. Gotchas + +- **Kein Container am Core** (arm 32-bit, 2,9 MB frei) — natives WG ist kein Container: ein paar Config-Zeilen. + AP-Flash-Enge (54 MB) ist hier **nicht** im Spiel. +- **MikroMCP-WG-Lücken** (TP16.1 §4.3): PrivateKey, `endpoint`-Zerlegung, `persistent-keepalive` → sshpass. +- **Name ohne Bindestrich** (`warpout`) für GC-Tauglichkeit. +- **WARP = geteilte CF-IP:** verbirgt die Heim-IP, ersetzt aber nicht „sauber" (manche Seiten flaggen VPN/CF-IPs). +- **Kein Auto-Failover:** stirbt WARP (Handshake weg), verlieren **Clients** den Internetzugang (Mark bleibt, + Interface ist L3-mäßig „up"); die **Router-Infra läuft weiter** über Liwest → Router bleibt per MikroMCP + erreichbar, Rollback §9. Netwatch-Failover = optional, später. +- **Verifikation über TCP/HTTP (curl),** nicht `nc -z` (trügt hinter Proxys, TP16.1 §4.5). + +## 11. Offen vor Start + +1. **TP-Nummer** + Gitea-Issue (User-Okay) + Prosa-Abschnitt. +2. Consumer-WARP-Konto (wgcf `register` = neues Wegwerf-Konto, geteilte IP, bewusst).