TP16.1 4.1-4.4 durch: Mesh-Tunnel steht auf crs326-core

Prereqs: use_zt_virtual_ip=true, Device-Profil 'Cloudflare Mesh', Split-Tunnel
auf beiden Profilen (100.64/10 -> /11 + 100.112/12).
Geraet: cf-mesh, 100.96.0.6/32, Peer 162.159.193.2:2408, Handshake steht,
Route 100.96.0.0/12 aktiv. Backup vorher (Auflage #4).
4.4 Weg A hat funktioniert - vnet-Gotcha trat NICHT ein.

Zwei Werkzeug-Fallen dokumentiert: MikroMCP manage_wireguard_interface kann
keinen Privkey annehmen (CF liefert ihn aber), und manage_wireguard_peer
verarbeitet endpoint 'IP:Port' falsch (endpoint-port=0 -> kein Handshake).

Offen: Dashboard-only-Schalter 'Allow all Cloudflare One traffic to reach
enrolled devices' + Ping-Abnahme 4.5.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-17 12:08:36 +02:00
parent 7388cc8388
commit 44c1fbcca8
2 changed files with 89 additions and 4 deletions

View File

@@ -1,6 +1,13 @@
# TP16.1 — Private Access via native Cloudflare Mesh (WARP Connector) auf dem CRS326 Core-Switch
> **✅ Status 2026-08-17: §4.0 DURCH — Plan-Gate offen, Mesh-Node existiert.** `POST /warp_connector` erfolgreich:
> **🟡 Status 2026-08-17: §4.0–§4.4 DURCH, Mesh-Tunnel steht — Abnahme (§4.5) offen.** `cf-mesh` auf
> `crs326-core` handshaked mit dem CF-PoP, CF meldet den Node **healthy**, und die Route `10.40.0.0/16` zeigt
> bereits auf ihn statt auf `bf-pve`. **Zwei Dinge fehlen noch, beide erfordern dich:** (1) der Dashboard-only-
> Schalter „Allow all Cloudflare One traffic to reach enrolled devices" (§4.1 Schritt 2), (2) die Ping-Abnahme mit
> verbundenem WARP (§4.5). Danach ist die Auflage aus Ausnahme #4 fällig: Ist-Stand als intended config zurück
> nach Nautobot.
>
> *Vorstufe:* **§4.0 DURCH — Plan-Gate offen, Mesh-Node existiert.** `POST /warp_connector` erfolgreich:
> **`bf-core-mesh` = `d1da7c8a-2736-4cbb-8af1-32db5393fb9c`**, Register-Token in `mcp/cloudflare/.env`
> (`CF_MESH_REGISTER_TOKEN`, gitignored, `chmod 600`). ➡️ **Die seit 2026-07-17 offene Free-Plan-Frage ist damit
> beantwortet: der Free-ZT-Plan erlaubt Cloudflare Mesh. Der LXC-Fallback (§6) ist vom Tisch.**
@@ -191,6 +198,32 @@ tunnel-spezifischen Doc-Seiten, die noch die alten Namen zeigen). Im Token-Edito
**„Cloudflare One Connector: WARP"** suchen (nicht „Tunnel"), **Edit** wählen. Für §4.4 zusätzlich
**„Cloudflare One Networks"** → Edit (Routes/vnets).
### 4.1 CF-Prerequisites — ✅ **ERLEDIGT 2026-08-17, bis auf einen Dashboard-Klick**
| Schritt | Stand |
|---|---|
| 1. Unique Device IP | ✅ `use_zt_virtual_ip: true` gesetzt (PATCH `devices/settings`) |
| 2. „Allow all Cloudflare One traffic to reach enrolled devices" | 🔴 **OFFEN — Dashboard-only, kein API-Feld** (s.u.) |
| 3. Device-Profil „Cloudflare Mesh" | ✅ `4d3c0f57-a717-49ac-ab92-b420e33e6380`, match `identity.email == "warp_connector@emsenhuber.cloudflareaccess.com"`, `tunnel_protocol=wireguard`, precedence 100 |
| 4. Split-Tunnel-Exclude | ✅ auf **beiden** Profilen: `100.64.0.0/10` raus, `100.64.0.0/11` + `100.112.0.0/12` rein (14→15 bzw. 16→15 Einträge) |
| 5. ICMP-Proxy | ✅ war schon an, nichts zu tun (s. §4.1.5) |
> 🔴 **Schritt 2 ist der einzige verbliebene Handgriff und NUR im Dashboard machbar.** Weder
> `PATCH /devices/settings` noch `POST /devices/policy` kennen ein entsprechendes Feld — im OpenAPI-Spec **und** in
> der GET-Antwort des Default-Profils taucht es nicht auf (gegengeprüft 2026-08-17). Es verhält sich damit genau
> wie das ICMP-Flag: Dashboard-only. **CF-Docs führen es als Mesh-Prerequisite („Mesh connectivity")**, es ist also
> nicht optional. Pfad: **Team & Resources → Devices → Device settings → Profil → „Allow all Cloudflare One traffic
> to reach enrolled devices"** einschalten. ⚠️ Laut CF-Doc ist das eine **Profil**-Einstellung — unser Runbook
> führte sie fälschlich als Account-Einstellung („gleiche Seite" wie Unique Device IP).
> 📎 **Nachtrag zu Schritt 3/4 aus den CF-Docs (gelesen 2026-08-17):** CF empfiehlt für Mesh-*Nodes* eigentlich ein
> Profil im **Include**-Modus mit `100.96.0.12` — das gilt für Nodes, die den **Cloudflare One Client** fahren.
> Unser Node ist **natives RouterOS-WireGuard** und konsumiert überhaupt kein Device-Profil; für ihn zählt
> ausschließlich die Routing-Config aus §4.3. Das Profil legen wir trotzdem an (Guide-konform, schadet nicht).
> Relevant ist die Exclude-Korrektur für die **Client**-Geräte (MacBook/iPhone) — und die ist gesetzt.
<details><summary>Ursprüngliche Schrittliste</summary>
### 4.1 CF-Prerequisites setzen (⚠️ account-weit, trifft LIVE-Geräte → 1× kurzer WARP-Reconnect einplanen)
1. **Unique Device IP AN:** `PATCH /accounts/…/devices/settings {use_zt_virtual_ip:true}` (Dashboard: Team & Resources →
Devices → Management → „Assign a unique IP address to each device").
@@ -211,7 +244,21 @@ tunnel-spezifischen Doc-Seiten, die noch die alten Namen zeigen). Im Token-Edito
nativ (kein Gateway-ICMP-Proxy im Pfad). **Trotzdem: nach dem Scharfschalten Ping gegengeprüft** (§4.5) — falls wider
Erwarten doch tot, hier zuerst schauen.
### 4.2 WireGuard-Config extrahieren (einmalig, ephemer)
</details>
### 4.4 Route-Umzug — ✅ **ERLEDIGT 2026-08-17, Weg A hat funktioniert**
`PATCH /teamnet/routes/5546dcb6-5901-4da6-8d91-b17f94703f71 {tunnel_id: d1da7c8a-…}` → `success: true`.
**Der befürchtete vnet-Gotcha ist NICHT eingetreten** — CF hat den PATCH auf einen `warp_connector`-Tunnel
anstandslos angenommen, obwohl die Route am vnet `1480b545…` hängt. Weg B (DELETE+POST) war nicht nötig und
bleibt nur als Fallback dokumentiert. `10.40.0.0/16` zeigt jetzt auf **`bf-core-mesh`** statt auf `bf-pve`.
**Rollback** unverändert 1 PATCH zurück auf `f7fdf3a6…` — `bf-pve` läuft weiter, nichts gelöscht.
### 4.2 WireGuard-Config extrahieren (einmalig, ephemer) — ✅ erledigt 2026-08-17
> **As-built:** gelaufen in **LXC 400 auf pve** (x86_64; der macmini ist arm64 — bei den cloudflared-Connectoren
> hatten wir dort schon eine arm64-Leiche). Ergebnis s. §4.3. Der `.conf` mit dem PrivateKey wurde nach dem
> Auslesen auf dem LXC **geshreddert** (`shred -u`) — der Schlüssel liegt jetzt nur noch in
> `mcp/cloudflare/.env` (`CF_MESH_PRIVKEY`, gitignored, `chmod 600`) und am Gerät.
Auf macmini oder pve (Docker vorhanden):
```
docker run --rm -v $(pwd):/app/output ghcr.io/animmouse/wgcf-connector <REGISTER_TOKEN>
@@ -222,7 +269,41 @@ ignorieren, wir bauen v4-only), **DNS** (CF-Resolver — ignorieren, ap1 hat eig
Registriert den Node via CF-API (macht Netz-Call), läuft danach nie wieder. **PrivateKey nach `mcp/cloudflare/.env`
o. `~/.secrets`** (nicht committen).
### 4.3 `crs326-core` nativ konfigurieren ✅ ausführungsreif (Werte finalisiert 2026-08-16)
### 4.3 `crs326-core` nativ konfigurieren — ✅ **AS-BUILT 2026-08-17**
**Ist-Stand am Gerät (verifiziert):**
| | |
|---|---|
| Interface | `cf-mesh`, MTU **1420**, `running`, listen-port 13279 (auto) |
| PublicKey (Gerät) | `vGkiAuQt8iHGtNkllTxMxjlgQhN9RtSTjC8qHwnccAw=` |
| Mesh-IP | **`100.96.0.6/32`** (v4-only, die mitgelieferte v6 `2606:4700:cf1:1000::6/128` bewusst ignoriert) |
| Peer | `bmXOC+F1FxEMF9dyiK2H5/1SUtzH0JuVo51h2wPfgyo=` @ **`162.159.193.2:2408`**, allowed `0.0.0.0/0`, keepalive 25s |
| Handshake | ✅ steht (`last-handshake` < 10s, rx/tx laufen) |
| Route | `100.96.0.0/12 → cf-mesh`, Flags **`A s`** (active/static) |
| Registrierung | `reg_id 01a00f2d-2316-12f6-90f6-c3f344469fb3`, CF-Node-Status **healthy**, 1 Connection |
| Backup vor dem Eingriff | `pre-tp16.1-mesh-20260817.backup` (Auflage Ausnahme #4 ✅) |
**Endpoint-Hinweis erledigt:** die Config lieferte direkt `162.159.193.2` — die im Guide beschriebene
Substitution `162.159.192.x → 162.159.193.x` war **nicht nötig**.
> ⚠️ **Zwei Werkzeug-Fallen, beide real getroffen — für die nächste WG-Arbeit wichtig:**
>
> 1. **MikroMCPs `manage_wireguard_interface` kann prinzipiell KEINEN privaten Schlüssel annehmen**
> („RouterOS generates the private key on create — it is never passed in"). Bei CF Mesh kommt der Key aber
> **von CF** — das Tool ist für diesen Fall also strukturell ungeeignet. Weg: `sshpass`+SSH mit
> `$CF_MESH_PRIVKEY` aus der gitignoreten `.env` **interpoliert**, damit der Schlüssel weder durch den
> Agent-Kontext noch ins MCP-Journal wandert; Fehlerausgabe vorher durch `sed` maskieren (Memory
> `feedback_redact_router_passwords_in_tracebacks`). Peer/IP/Route liefen danach regulär über
> `plan_changes` → `apply_plan`.
> 2. **`manage_wireguard_peer` verarbeitet `endpoint: "IP:Port"` falsch:** es schreibt den *ganzen* String nach
> `endpoint-address` und lässt `endpoint-port=0` → **kein Handshake**, rx/tx bleiben 0. Das sieht aus wie ein
> Netz-/Firewall-Problem, ist aber ein Parameter-Bug. Fix: `/interface/wireguard/peers/set [find …]
> endpoint-address=<IP> endpoint-port=<Port>`. **Nach jedem Peer-Add per MikroMCP `print detail` gegenlesen.**
> 3. Ebenso ohne Parameter im Tool: **`persistent-keepalive`** → separat per `run_command` setzen.
<details><summary>Ursprünglicher Plan (Stand 2026-08-16)</summary>
> Der frühere Platzhalter-Vorbehalt („Management-IP/Interface-Zuordnung fehlt") ist erledigt: Zielgerät ist
> **`crs326-core`** (Mgmt `10.40.99.1`, MikroMCP-routerId `crs326-core`). Offen bleibt nur, was erst zur Laufzeit
@@ -259,6 +340,8 @@ o. `~/.secrets`** (nicht committen).
Ist-Stand als intended config zurück nach Nautobot. **Scope:** nur der Mesh-Bring-up auf `crs326-core`, nicht
spätere WG-Änderungen, nicht andere Geräte. Vorher `/system backup` (TP22-Regel 3).
</details>
#### Und wie hält man Secrets langfristig aus der Config raus?
Die Ausnahme soll ein **einmaliger Bootstrap** bleiben, kein Dauerzustand. Der Denkfehler, den man vermeiden