docs: Plan WARP-Egress (nativer Consumer-WARP als WG auf crs326-core)
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 <noreply@anthropic.com>
This commit is contained in:
132
docs/warp-egress-native-crs326.md
Normal file
132
docs/warp-egress-native-crs326.md
Normal file
@@ -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="<CF_WARP_CLIENT_PRIVKEY>" 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-<datum>.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 `<<REDACTED>>` (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).
|
||||||
Reference in New Issue
Block a user