docs: WARP-Egress-Versuch dokumentiert — Cloudflare blockt Consumer-WARP-WG-Clients
Consumer-WARP über natives RouterOS-WG gebaut, verifiziert, zurückgebaut. Befund: Handshake rx=0, Cloudflare blockt inoffizielle WG-Clients (reserved/Client-ID + Abuse-Prevention). Weg: Dedicated Egress. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,132 +1,53 @@
|
||||
# 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**.
|
||||
|
||||
---
|
||||
> **Status:** ❌ **VERWORFEN 2026-09-26** — Cloudflare blockt inoffizielle Consumer-WARP-WireGuard-Clients.
|
||||
> Live gebaut, verifiziert, dann vollständig zurückgebaut. Key + Backup bleiben zur Nachvollziehbarkeit liegen.
|
||||
|
||||
## 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).
|
||||
- Cannaleo-Origin `164.90.191.7` (blaueblueten.de, DigitalOcean multi-tenant, ~400 Vhosts) blockt die Heim-IP
|
||||
`90.146.33.177` hart (leerer `403`, live 2026-09-25).
|
||||
- **Scope (User-Vorgabe 2026-09-25):** nicht der ganze Outbound, sondern **genau eine Ziel-IP**
|
||||
(`164.90.191.7/32` — blaueblueten.de apex + www, beide identisch). Nur **Privatbestellungen**, Traffic
|
||||
überschaubar gering.
|
||||
- **Terpenfinder wird NICHT über diesen Weg** in Betrieb genommen (eigene, saubere Lösung — siehe §5).
|
||||
|
||||
## 2. Entscheidung & Nicht-Ziele
|
||||
## 2. Was gebaut wurde (2026-09-26, live)
|
||||
|
||||
- **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.
|
||||
1. **Consumer-WARP-Key** per `wgcf` registriert (ViRb3 v2.3.0, Wegwerf-Konto via `api.cloudflareclient.com`).
|
||||
→ `mcp/cloudflare/.env` (`CF_WARP_CLIENT_PRIVKEY`, gitignored) + `~/.secrets/wgcf-client/` (account + profil).
|
||||
2. Auf `crs326-core` (WG-Zeilen via `sshpass -e`, Rest per MikroMCP/ssh):
|
||||
- `/interface wireguard add name=warpout mtu=1280 private-key=… comment="WARP Egress (privat)"`
|
||||
- Peer `warp-cf-pop`: public-key `bmXOC+F1FxEMF9dyiK2H5/1SUtzH0JuVo51h2wPfgyo=`,
|
||||
endpoint `engage.cloudflareclient.com:2408`, `allowed-address=0.0.0.0/0`, `persistent-keepalive=25s`
|
||||
- `/ip address add 172.16.0.2/32 interface=warpout`
|
||||
- `/routing table add name=warpout fib` + `/ip route add 0.0.0.0/0 gateway=warpout routing-table=warpout`
|
||||
- `/routing rule add dst-address=164.90.191.7/32 action=lookup-only-in-table table=warpout`
|
||||
- NAT `masquerade out-interface=warpout` + forward `accept out-interface=warpout`
|
||||
3. **Verifiziert:** Key korrekt (abgeleiteter Public-Key == Router-Public-Key
|
||||
`HTFM3gj3FyT0EjWkG+2LLmvtxaFz1kH/P1iDwM0HswI=`), Konto „Active" (`wgcf status`).
|
||||
|
||||
## 3. Ist-Stand (live 2026-09-25)
|
||||
## 3. Befund: Handshake schlägt fehl
|
||||
|
||||
- `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.
|
||||
- Peer `warp-cf-pop`: `rx=0`, kein `last-handshake` — Cloudflare antwortet **nie** auf den WG-Handshake,
|
||||
egal welcher Endpoint (`162.159.192.1` / `.193.2` / `.193.5`).
|
||||
- **Ursache (recherchiert):** Cloudflare blockt **inoffizielle WireGuard-Clients** für Consumer-WARP. Der
|
||||
offizielle Client setzt ein spezielles Handshake-Feld (`reserved`/Client-ID, z. B. `b91981`), das RouterOS
|
||||
(und jedes plain-wgcf-Profil) nicht setzt; dazu Abuse-Prevention. Der Mesh-Connector `cf-mesh` läuft nur,
|
||||
weil das ein **anderes Produkt** ist (Zero Trust, nicht Consumer).
|
||||
- Quellen: [ViRb3/wgcf Issue #542](https://github.com/ViRb3/wgcf/issues/542) ·
|
||||
[#515](https://github.com/ViRb3/wgcf/issues/515) · [#158](https://github.com/ViRb3/wgcf/issues/158).
|
||||
|
||||
## 4. CF-MCP: Account verifizieren (read-only, Schritt 0)
|
||||
## 4. Abbau (2026-09-26)
|
||||
|
||||
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.
|
||||
- Alle 8 Objekte entfernt (Routing-Regel, Route, Tabelle, NAT, Firewall, Adresse, Peer, Interface). Core
|
||||
wieder im Ursprungszustand — **keine Drift**, Golden-Config-Compliance unverändert.
|
||||
- Backup `pre-warp-egress-20260925.backup` liegt auf dem Core (vor dem Versuch, TP22-Regel).
|
||||
- `CF_WARP_CLIENT_PRIVKEY` bleibt in `mcp/cloudflare/.env` (nutzlos, da Client geblockt; kann bei Bedarf entfernt werden).
|
||||
|
||||
## 5. Einmalig: Consumer-WARP-Key (wgcf, nicht wgcf-connector)
|
||||
## 5. Weg vorwärts
|
||||
|
||||
```
|
||||
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).
|
||||
- **Dedicated Egress IP** (Cloudflare, paid) = die „saubere Lösung". Geteilte CF-IP genügt nicht — der Origin
|
||||
blockt offenbar auch geteilte CF-IPs (offizielles WARP am Client liefert laut Test ebenfalls `403`).
|
||||
- Alternativ: offizielles WARP am Client (Handshake funktioniert dort, aber `403`).
|
||||
- **Nicht nochmal probieren:** Consumer-WARP über natives RouterOS-WG ist auf absehbare Zeit blockiert.
|
||||
|
||||
Reference in New Issue
Block a user