TP31 -- Caddy als Reverse Proxy fuer innen UND aussen, cloudflared von sechs Containern auf einen. Anlass war Christophs Einwand, er habe den Core unter der Praemisse gekauft, dass auch die Public-Apps darueber laufen. Aktenlage geprueft: eine Zusage gibt es nicht, aber TP16.1 begruendet die Auswahl mit seinem Prinzip 'Router = einziger SPOF' -- und niemand hat je geprueft, ob der oeffentliche Strang ohne sechs Container auskommt. Keine Taeuschung, eine ungepruefte Annahme. - dst-nat-Variante geprueft und verworfen (ginge, Free-Tarif reicht), weil Christophs Tunnel-Variante drei Risiken spart: keine angreifbare Origin-IP, keine CF-IP-Allowlist, kein DDNS als Voraussetzung - cloudflared auf ap1/ap2: live gemessen arm64, 95 MB Flash frei, 690 MB RAM frei. Der Core kann es nie (arm 32-bit, 2,9 MB frei) - Kriterium fuer Infrastruktur-Container: was sich selten aendert und wenig schreibt. Caddy nein (Config aendert staendig), AGH nein (Query-Log frisst NAND) TP32 -- VMID-Systematik (Hunderter = Klasse, gemeinsamer Raum fuer VMs und LXCs) + letztes Oktett je /24, uebertragbar auf andere Standorte. đŽ Dabei gefunden und SOFORT REPARIERT: die Startreihenfolge war falsch. Proxmox startet erst Gaeste mit explizitem startup order=, dann den Rest nach VMID -- drei Gaeste hatten einen, die DBs nicht. Home Assistant startete damit vor MariaDB, MQTT und z2m25. Jetzt fuenf Stufen (Core/Daten/Platform/Broker/Apps). Erkenntnis: VMID = Klassifikation, startup order = Abhaengigkeit -- die Umnummerierung muss den Startlauf gar nicht reparieren. Doku-Korrekturen aus den Messungen: - CLAUDE.md: 'Container NICHT auf dem Router' war nie nachgemessen - tp16.1: 'Connector als Container â' galt dem TUN-Bedarf des WARP-Connectors; cloudflared braucht kein TUN - cf-tunnel-mapping Paragraph 16: die macvlan-Blindheit war mit einem Shim behebbar -- der Workaround war groesser als der Fix Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
552 lines
44 KiB
Markdown
552 lines
44 KiB
Markdown
# TP16.1 â Private Access via native Cloudflare Mesh (WARP Connector) auf dem CRS326 Core-Switch
|
||
|
||
> # â
**TP16.1 ABGESCHLOSSEN â 2026-08-17**
|
||
> Der private Zugang lĂ€uft ĂŒber **natives WireGuard auf `crs326-core`** statt ĂŒber den cloudflared-QUIC-Proxy.
|
||
> **ICMP ist damit repariert: 0 % Loss auf alle BF-VLANs (vorher 100 %)** â genau das Symptom aus dem Incident
|
||
> vom 2026-07-16, das dieses TP ausgelöst hat. Die öffentlichen FQDNs blieben unberĂŒhrt auf dem 3-Tunnel-HA
|
||
> (TP16). Auflage aus Ausnahme #4 erfĂŒllt: **68/68 compliant, keine Drifts.**
|
||
>
|
||
> **Die drei Erkenntnisse, die Zeit gekostet haben und beim nÀchsten Mal Zeit sparen:**
|
||
> 1. Der Blocker war nie der Free-Plan, sondern der **API-Token** (§4.0) â Mesh ist im Free-ZT-Plan erlaubt.
|
||
> 2. **`/ip service address=10.40.0.0/16` sperrt das Router-Mgmt aus dem Mesh aus** (§4.5) â Ping geht,
|
||
> Management nicht. FĂŒr `branch`/`ap1`/`ap2` noch offen.
|
||
> 3. **MikroMCP taugt fĂŒr WireGuard nur halb** (§4.3): kein Privkey möglich, und `endpoint="IP:Port"` wird
|
||
> falsch zerlegt â kein Handshake.
|
||
>
|
||
> â
**Nachlauf am selben Tag, ebenfalls abgeschlossen:** die **Mgmt-ACL wurde via Golden Config auf alle vier
|
||
> GerĂ€te ausgerollt** (neue Compliance-Feature `ip-service`, **72/72 compliant**) â s. §4.7. Und der
|
||
> Dashboard-Schalter ist **recherchiert und bewusst AUS** â s. §4.1 Schritt 2. **TP16.1 hat damit keine
|
||
> offenen Punkte mehr**, auĂer den weiterhin getrennt gefĂŒhrten Fremdthemen (TP16-HA, TP5-Firewall). `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.**
|
||
> **Am GerĂ€t ist weiterhin nichts angefasst** (kein Backup, kein `cf-mesh`, keine Route) â nĂ€chster Schritt ist
|
||
> §4.1, und der ist wegen des account-weiten WARP-Reconnects **user-gated**.
|
||
>
|
||
> *Historie dieses Anlaufs: 2026-08-16 blockiert auf Token-Scope (zwei fehlende Permissions, s. §4.0) â
|
||
> 2026-08-17 Token neu aufgesetzt, jetzt account-owned.* `crs326-core` ist seit 2026-08-08 der produktive L3-Router und seit 2026-08-13 in Nautobot adoptiert (68/68 compliant) â die Bedingung âgated bis TP21 den CRS326 abdeckt" ist **erfĂŒllt**. §3 am 2026-08-16 neu gemessen, §4.3 von Platzhalter auf **ausfĂŒhrungsreif** gezogen, **Governance-Ausnahme #4 erteilt** (WG-Zeilen direkt, weil ein Privkey ĂŒber Golden Config strukturell nicht deploybar ist). Scharfschalten bleibt eine **eigene Session** â es fasst account-weite WARP-Einstellungen an.
|
||
> *Historie: Konzept + Runbook 2026-07-16 · Recherche verifiziert + gehÀrtet 2026-07-17 · Ziel-Device von ap1 auf CRS326 retargeted 2026-07-22.*
|
||
> â ïž **Retarget-Hinweis (2026-07-22, Stand 2026-08-16 aufgelöst):** Alles unten war ursprĂŒnglich fĂŒr **ap1** geschrieben und wurde auf den **CRS326 Core-Switch** ummĂŒnzt. ~~Der CRS326 ist aktuell noch Werkszustand â Management-IP/Interface-Zuordnung TBD, §4.3 ist ein Platzhalter.~~ â **ĂŒberholt:** `crs326-core` ist produktiver L3-Router mit Mgmt `10.40.99.1`, §4.3 trĂ€gt jetzt echte Werte. Grund fĂŒr den Retarget: TP15-Endstand (kein RB5009, Router bleibt ap1/ap2 rein fĂŒr L3/WLAN) + TP21s Modell "ganzer Kabel-Fabric via RouterOS" â der CRS326 wird ohnehin Nautobot-verwaltet, ap1 bleibt Public-Edge/WLAN-Anker.
|
||
> Selbst-tragend: eine frische Session kann das mit diesem Doc + `docs/cf-tunnel-mapping.md` straight bauen â vorausgesetzt der CRS326-Bring-up (TP15) und die Nautobot-Adoption (TP21) stehen.
|
||
> SSoT-Kontext: `docs/cf-tunnel-mapping.md` §13/§14, Memory `project_cf_tunnel_1033`.
|
||
> HÀrtungs-Delta 2026-07-17 (gilt unabhÀngig vom ZielgerÀt): Split-Tunnel auf BEIDEN Profilen (§4.1.4), vnet-Gotcha + Weg B beim Route-Umzug (§4.4),
|
||
> v4-only-Entscheid (IPv6-site-to-site laut Guide broken), Quellen verifiziert (§2). **Korrektur:** ICMP-Proxy ist bereits AN
|
||
> (fm-Ping `10.101.0.0/24` beweist es) â kein To-Do, s. §4.1.5.
|
||
|
||
## 1. Warum ĂŒberhaupt / Root Cause
|
||
|
||
**Incident 2026-07-16 (unterwegs):** keine BF-IPs ĂŒber WARP. Diagnose:
|
||
- **TCP ĂŒber den CF-WARP-Pfad funktioniert** (SSH, alle Web-UIs, MCP-Endpoints erreichbar) â
|
||
- **ICMP ist strukturell kaputt.** DreilĂ€nder-Ping-Befund: fm **36 % Loss** (ICMP-Proxy ĂŒber QUIC-Connector,
|
||
funktioniert aber mies), bf **100 %** (macmini-Connector lĂ€uft seit dem http2-Fix von heute = QUIC-los â
|
||
ICMP-unfÀhig; zusÀtzlich cloudflared-Container ohne Ping-Sockets), dw **100 %** (192.168.0.0/16 steht in der
|
||
WARP-Split-Tunnel-Exclude â Pings betreten den Tunnel gar nicht).
|
||
|
||
**Kernursache:** cloudflared ist **kein** WireGuard, sondern ein QUIC/HTTP2-L7/L4-Proxy. ICMP darĂŒber ist
|
||
Zusatz-Gefrickel (Account-ICMP-Flag + QUIC-Transport + `ping_group_range`-sysctl je Host) und war nie
|
||
zuverlĂ€ssig eingerichtet. **Der WARP-Client selbst spricht WireGuard** â die passende Gegenstelle fĂŒr einen
|
||
*sauberen* privaten L3-Zugang ist deshalb **Cloudflare Mesh (WARP Connector)**, ebenfalls WireGuard.
|
||
|
||
## 2. Entscheidungsweg (was verworfen wurde und warum)
|
||
|
||
- **WG-Roadwarrior (eigene WG-Peers je GerĂ€t):** â verworfen â User will KEINE Extra-App/kein Profil pro GerĂ€t.
|
||
âEin Client = WARP fĂŒr alles" bleibt Anforderung.
|
||
- **Alle ZT-Anbieter mit Helper-Host** (CF WARP Connector als Daemon-Host, Tailscale, NetBird, Twingate):
|
||
brauchen dauerhaft einen Linux-Host â verletzt âRouter = einziger SPOF, keine AbhĂ€ngigkeit zu anderen Rechnern".
|
||
- **Connector als RouterOS-Container:** â nicht möglich â RouterOS-7-Container haben **kein `/dev/net/tun`-
|
||
Passthrough**; der WARP-Connector-Daemon braucht ein TUN-Device. Gilt auf **jeder** Router-/Switch-HW (hAP axÂČ/axÂł/CRS326/RB5009 â RB5009 mittlerweile ohnehin nicht mehr geplant, s. TP15).
|
||
â **hAP axÂł löst das NICHT** (und ist zudem Wi-Fi 6, nicht 7 â kein WLAN-Gewinn ggĂŒ. axÂČ). HW-Kauf ist vom
|
||
Tunnel-Fix **entkoppelt**.
|
||
- **â
GewĂ€hlt: Cloudflare Mesh als NATIVES WireGuard-Interface auf dem CRS326 Core-Switch** (Retarget 2026-07-22, ursprĂŒnglich ap1). Cloudflare Mesh spricht WireGuard,
|
||
RouterOS kann natives WireGuard (der TP10-Hub auf ap1 *ist* schon einer, Muster ĂŒbertrĂ€gt sich). Ein Mesh-Node wird als WG-Peer zu einem
|
||
CF-PoP registriert â **kein Container, kein TUN, kein LXC, keine neue HW.** Der CRS326 ist der zentrale Kabel-Fabric-Knoten
|
||
und sieht ohnehin alle VLANs; ap1 bleibt Public-Edge/WLAN-Anker, ĂŒbernimmt aber nicht mehr die Mesh-Node-Rolle. ICMP/TCP/UDP nativ.
|
||
|
||
Quelle/Vorlage: animmouse âSetup Cloudflare Mesh on MikroTik" + âSetup Cloudflare Mesh using WireGuard".
|
||
Ehrliche EinschrĂ€nkung: **von uns noch nicht gebaut** â starker, technisch schlĂŒssiger Lead; echter Beweis = bauen+pingen.
|
||
|
||
**â
Recherche verifiziert (2026-07-17, PrimÀrquellen gelesen + offizielle CF-Docs + OpenAPI-Spec):**
|
||
- **Produkt-Status:** âWARP Connector" heiĂt seit **2026-04-14 offiziell âCloudflare Mesh"** (Rebranding, kein Migrationszwang);
|
||
Node-Limit **50/Account**; neues Dashboard unter **Networking â Mesh** (interaktive Map, Route-Config, Setup-Wizard).
|
||
Die API-Pfade heiĂen weiterhin `/accounts/{id}/warp_connector` â im OpenAPI-Spec bestĂ€tigt: POST (create),
|
||
GET `âŠ/{tunnel_id}/token` (Register-Token), dazu sogar **HA-Endpoints** (`âŠ/configurations` active-passive-Replicas,
|
||
`âŠ/failover`) â fĂŒr uns nicht nötig (ap1 = bewusster SPOF), aber gut zu wissen.
|
||
- **CIDR-Routes fĂŒr Mesh-Nodes** laufen ĂŒber dieselbe `teamnet/routes`-API wie cloudflared (`POST {network, tunnel_id: <mesh_node_id>}`,
|
||
Token-Scope `Cloudflare One Networks Write` oder `Cloudflare Tunnel Write`) â unser `CF_API_TOKEN`-Pfad passt.
|
||
- **animmouse-MikroTik-Rezept bestÀtigt** (alle Kommandos gegengelesen, s. §4.3): CF-Wellknown-PublicKey, Endpoint-Substitution
|
||
`162.159.192.x â 162.159.193.x` (Latenz), MTU 1420, `100.96.0.0/12 â cf-mesh`-Route. Guide nutzt `persistent-keepalive=1m`
|
||
(unser Entwurf sagte 25s â beides ok, 25s konservativer hinter NAT; wir sind Public-Edge â 1m reicht).
|
||
- **IPv6-Befund (animmouse):** Mesh-site-to-site-IPv6 war beim Guide-Test **broken** (NAT66-Workaround nötig) â **wir bauen bewusst v4-only**
|
||
(kein v6 auf `cf-mesh`, kein NAT66 â BF nutzt intern eh kein v6, s. Memory `project_ipv6_state`).
|
||
- **Sources:** [Setup Cloudflare Mesh on MikroTik](https://www.animmouse.com/p/setup-cloudflare-mesh-on-mikrotik/) ·
|
||
[Setup Cloudflare Mesh using WireGuard](https://www.animmouse.com/p/setup-cloudflare-warp-connector-using-wireguard/) ·
|
||
[wgcf-connector (GitHub)](https://github.com/AnimMouse/wgcf-connector) ·
|
||
[CF-Changelog âIntroducing Cloudflare Mesh"](https://developers.cloudflare.com/changelog/post/2026-04-14-cloudflare-mesh/) ·
|
||
[CF-Docs Mesh Routes](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-mesh/routes/)
|
||
|
||
## 3. Ist-Stand Account (**neu gemessen 2026-08-16**, read-only â CF-API + MikroMCP)
|
||
|
||
> Die Messung vom 2026-07-16 ist auf der **CF-Seite unverÀndert** geblieben; auf der **GerÀteseite** hat
|
||
> sich alles geÀndert (Core-Cutover 2026-08-08, Nautobot-Adoption 2026-08-13). Beides unten getrennt.
|
||
|
||
**Cloudflare (alle Werte am 2026-08-16 gegengeprĂŒft, identisch zu 2026-07-16):**
|
||
- Team-Domain: **`emsenhuber.cloudflareaccess.com`** â Mesh-Node-IdentitĂ€t = `warp_connector@emsenhuber.cloudflareaccess.com`
|
||
- **Noch KEIN** `warp_connector`-Tunnel (`GET /accounts/âŠ/warp_connector` = `[]`). Wichtig: der GET **antwortet**
|
||
(kein 403) â die Plan-Frage entscheidet sich also erst am `POST` (§4.0).
|
||
- `devices/settings`: **`use_zt_virtual_ip: false`** â Unique-Device-IP weiterhin **AUS**, muss fĂŒr Mesh AN.
|
||
`gateway_proxy_enabled: true`, `gateway_udp_proxy_enabled: true` (ICMP-Flag ist Dashboard-only, s. §4.1.5).
|
||
- **Genau EIN Device-Profil** (das Default-Profil `0197d1b3-d98a-7c24-b70c-a4d89df7583b`, `service_mode_v2: warp`).
|
||
âĄïž Der âauf BEIDEN Profilen"-Hinweis in §4.1.4 meint deshalb: **Default jetzt, Mesh-Profil sobald es in Schritt 3
|
||
angelegt ist** â es gibt aktuell kein zweites, auf dem man etwas vergessen könnte.
|
||
- Split-Tunnel-Modus = **Exclude**; die Liste enthÀlt weiterhin **`100.64.0.0/10`** (schluckt die Mesh-Overlay-Range
|
||
`100.96.0.0/12`) und **kein** `10.0.0.0/8` â `10.40.0.0/16` lĂ€uft schon heute ĂŒber WARP (= warum TCP geht).
|
||
Nebenbefund: `192.168.0.0/16` steht drin â das ist die ErklĂ€rung fĂŒr die 100 % Ping-Loss nach **dw**, unabhĂ€ngig von diesem TP.
|
||
- vnet-Route `10.40.0.0/16` (vnet `1480b545âŠ` = `vnetemsenhuber`, **default**, Route-ID
|
||
**`5546dcb6-5901-4da6-8d91-b17f94703f71`**) zeigt weiterhin auf **cfd_tunnel `bf-pve`** (`f7fdf3a6âŠ`).
|
||
Bleibt der **Fallback**, bis Mesh bewiesen ist â vorher nichts löschen.
|
||
â ïž **Neu zu wissen:** `bf-pve` fĂ€hrt aktuell nur **einen** Connector (statt zwei, s. TP16-HA-Befund 2026-08-16) â
|
||
der private Pfad hĂ€ngt damit heute an einem einzelnen cloudflared-Prozess. Ein weiteres Argument fĂŒr das Mesh,
|
||
aber **kein** Ersatz fĂŒr die HA-Reparatur der öffentlichen Tunnel.
|
||
- `CF_API_TOKEN` ist `active` (verify OK). Ob er die separate Permission **âCloudflare One Connector: WARP"** trĂ€gt,
|
||
lĂ€sst sich nur durch den `POST` in §4.0 feststellen â genau dort schlug es am 2026-07-17 mit `10000` fehl.
|
||
|
||
**GerĂ€teseite â die alten Zeilen hier waren ĂŒberholt, Neufassung 2026-08-16:**
|
||
- ~~âCRS326 = Werkszustand, keine WireGuard-Config, keine Management-IP"~~ â **falsch seit dem Core-Cutover.**
|
||
`crs326-core` ist der **produktive L3-Router** (RouterOS 7.19.5): Mgmt `10.40.99.1` (vlan99), Gateway `.1` in
|
||
**jedem** VLAN, WAN `vlan100` mit der öffentlichen `90.146.33.177`, NAT, DHCP, DNS.
|
||
- ~~âap1-WireGuard: 1 Interface `wg-hub`"~~ â **wg-hub liegt seit 2026-08-08 auf dem Core**, nicht mehr auf ap1
|
||
(listen 51821, MTU 1412, Peers `fm` 10.101.0.0/24 + `dw` 10.95.10.0/24, beide handshaken). Das ist TP10 und
|
||
bleibt unangetastet â aber es ist jetzt das **direkte Vorbild auf demselben GerĂ€t**: das Mesh-Interface entsteht
|
||
daneben, nicht auf einem fremden Blatt.
|
||
- â
**Die offene Frage âRĂŒckweg-Routing TBD" aus §4.3 ist damit beantwortet:** der Core *ist* der L3-Router aller
|
||
VLANs, RĂŒckverkehr aus `10.40.0.0/16` zum Mesh-Interface braucht **keine** Zusatzroute.
|
||
- `crs326-core` ist seit 2026-08-13 in Nautobot adoptiert und compliance-verwaltet (68/68) â damit ist das
|
||
Gate âgated bis TP21 den CRS326 abdeckt" **erfĂŒllt**.
|
||
|
||
## 4. Runbook (nĂ€chste Session â Reihenfolge)
|
||
|
||
### 4.0 Plan-Probe (billig, reversibel) â ZUERST
|
||
`POST /accounts/{account_id}/warp_connector {name:"bf-ap1-mesh"}` via `CF_API_TOKEN` (curl/Bearer â der `cloudflare`-
|
||
MCP ist read-only, s. §11 der Mapping-Doc). Erfolgt der Create â Mesh ist im Free-ZT-Plan erlaubt. Scheitert er mit
|
||
Plan-/Auth-Fehler â **Stopp, Fallback = LXC-auf-pve-WARP-Connector** (alter Plan, ebenfalls dokumentiert).
|
||
Token danach: `GET /accounts/âŠ/warp_connector/{tunnel_id}/token` â das ist das `eyJhIjoiâŠIn0=`-Register-Token.
|
||
|
||
**đŽ STAND 2026-08-16: Plan-Probe erneut ausgefĂŒhrt â identisch gescheitert, Blocker jetzt vollstĂ€ndig vermessen.**
|
||
`POST /accounts/âŠ/warp_connector {"name":"bf-core-mesh"}` â `{"success":false,"errors":[{"code":10000,
|
||
"message":"Authentication error"}]}`, HTTP **403**. Der Token (`455e4f8eâŠ`) ist `active`. Gegenproben mit
|
||
**demselben** Token, um Scope von Plan-Gate zu trennen:
|
||
|
||
| Endpoint | Methode | Ergebnis | Bedeutet |
|
||
|---|---|---|---|
|
||
| `warp_connector` | GET | **200** (`[]`) | Endpoint existiert fĂŒr den Account, Feature nicht wegge-403-t |
|
||
| `warp_connector` | POST | **403** `10000` | â §4.0 â Permission `Cloudflare One Connector: WARP` fehlt |
|
||
| `cfd_tunnel` | GET | 200 | `Cloudflare Tunnel`-Scope vorhanden (TP16-Strang unberĂŒhrt) |
|
||
| `teamnet/routes` | GET | 200 | §4.4-Pfad grundsÀtzlich da (PATCH-Edit 2026-07-17 bewiesen) |
|
||
| `devices/settings` | GET | **403** `9109` | â **NEU: §4.1 ist ebenfalls blockiert** â `Zero Trust`-Scope fehlt |
|
||
| `user/tokens/{id}` · `tokens/permission_groups` | GET | 403 `9109` | Token kann sich selbst nicht introspizieren â Scope-Liste nur im Dashboard |
|
||
|
||
â ïž **Der wichtigste neue Befund: das Runbook nannte bisher NUR die eine fehlende Permission (§4.0).** Die Probe
|
||
zeigt, dass auch **§4.1 komplett scheitern wĂŒrde** â `devices/settings` ist fĂŒr den Token schon lesend dicht.
|
||
Ohne diesen Nachtrag hĂ€tte die Scharfschalt-Session den Token **zweimal** nachziehen mĂŒssen. Beides in **einem**
|
||
Edit erledigen.
|
||
|
||
**Gegenprobe, dass es NICHT das Free-Plan-Gate ist:** derselbe `devices/settings`-GET liefert ĂŒber den
|
||
`cloudflare`-**MCP** (OAuth, read-only, volle Account-Sicht) sauber `200` mit
|
||
`{gateway_proxy_enabled:true, gateway_udp_proxy_enabled:true, use_zt_virtual_ip:false}`. Der Account *kann* das
|
||
also â nur der Token darf nicht. âĄïž **Die Free-Plan-Frage aus §4.0 bleibt damit weiterhin unentschieden**: sie
|
||
beantwortet sich erst beim Retry des `POST` mit korrekt gescoptem Token. Erst ein dann *immer noch* fehlschlagender
|
||
POST wĂ€re das Plan-Gate und wĂŒrde den LXC-Fallback (§6) auslösen.
|
||
|
||
**â
AUFGELĂST 2026-08-17 â Token neu aufgesetzt, alle Proben 200.** Der Weg dahin hatte zwei Stolpersteine, die
|
||
man kennen muss, weil beide *aussehen* wie âToken kaputt", es aber nicht sind:
|
||
|
||
1. **Der neue Token ist ACCOUNT-OWNED** (id `9984078812bc18d4ebb6a64b570144f2`, gĂŒltig bis **2027-01-09** â°).
|
||
Account-Tokens verifizieren an einem **anderen** Endpoint: `GET /accounts/{account_id}/tokens/verify`.
|
||
â ïž Am alten `GET /user/tokens/verify` antwortet ein gĂŒltiger Account-Token mit **`1000 "Invalid API Token"`/401** â
|
||
zeitgleich liefern *alle* echten Endpoints 200. **Nicht als abgelaufen fehldeuten.**
|
||
2. **Dashboard-Fehler `"Account tag in access policy must match tag in request uri"`** (real erlebt, mehrfach):
|
||
tritt auf, wenn eine **Zone**-Permission (hier `DNS`) in dieselbe Policy-Zeile gepackt wird, die **Account**-
|
||
Ressourcen trÀgt. Zone-Permissions brauchen eine **eigene Policy-Zeile** mit Zone-Ressourcen. Halb richtig
|
||
gesetzt = Permission sichtbar, aber jede Zone `403`, weil keine Zone eingeschlossen ist.
|
||
|
||
**Verifiziertes Soll-Set (alle am 2026-08-17 mit 200 gegengeprĂŒft) â Dashboard sagt âEdit", die API sagt âWrite":**
|
||
|
||
| Dashboard | API-Name | Permission-ID | braucht |
|
||
|---|---|---|---|
|
||
| Cloudflare One Connector: WARP â Edit | `Cloudflare One Connector: WARP Write` | `5b5c774a5d174ca88d046c8889648b3f` | §4.0 |
|
||
| Zero Trust â Edit | `Zero Trust Write` | `b33f02c6f7284e05a6f20741c0bb0567` | §4.1 |
|
||
| Cloudflare One Networks â Edit | `Cloudflare One Networks Write` | `e2980d9241cf4939bbbd74fdc43b9651` | §4.4 |
|
||
| Cloudflare Tunnel â Edit | `Cloudflare Tunnel Write` | `c07321b023e944ff818fec44d8203567` | TP16 |
|
||
| Access: Apps and Policies â Edit | `Access: Apps and Policies Write` | â | Bestand |
|
||
| Access: Organizations, IdP, and Groups â Edit | `⊠Write` | â | Bestand |
|
||
| **Zone** DNS â Edit (`emsenhuber.net`) | `DNS Write` | â | Tunnel-CNAMEs |
|
||
|
||
â ïž **Namensfalle:** `Cloudflare One Connectors Write` (Plural, Sammelgruppe) ist **nicht** die Mesh-Permission.
|
||
Ebenso heiĂt âCloudflare Tunnel" in neueren Listen zusĂ€tzlich âCloudflare One Connector: cloudflared" â beide
|
||
Gruppen existieren parallel. VollstÀndige Liste (396 Gruppen) via MCP: `GET /user/tokens/permission_groups`.
|
||
|
||
<details><summary>Historischer Klickpfad (2026-08-16, vor der Auflösung)</summary>
|
||
|
||
**âĄïž Was zu tun ist (Dashboard, nur der User â Token-Bearbeitung ist keine Agent-Aktion):**
|
||
`dash.cloudflare.com` â My Profile â API Tokens â Token `455e4f8eâŠ` â Edit â **Account**-Permissions ergĂ€nzen:
|
||
1. **âCloudflare One Connector: WARP" â Edit** (§4.0: `POST /warp_connector` + `/token`)
|
||
2. **âZero Trust" â Edit** (§4.1: `devices/settings` PATCH, `devices/policy` POST, Split-Tunnel PUT)
|
||
3. **âCloudflare One Networks" â Edit** (§4.4 Routes/vnets â GET geht heute, Edit war 2026-07-17 ok; sicherheitshalber mitnehmen)
|
||
|
||
Danach neuen Wert nach `mcp/cloudflare/.env` **und** `~/.secrets/credentials.env` (beide tragen `CF_API_TOKEN`).
|
||
</details>
|
||
|
||
**â ïž Token-Permission-Gotcha (2026-07-17, real erlebt â Ursachenanalyse, weiterhin gĂŒltig):** `POST /warp_connector` schlug mit `code 10000
|
||
"Authentication error"` (HTTP 403) fehl, obwohl der `CF_API_TOKEN` gĂŒltig ist und `teamnet/routes` PATCHen kann.
|
||
Ursache: Cloudflare hat beim WARP-ConnectorâMesh-Rebranding (2026-04-14) eine **eigene, separate Permission-Group**
|
||
eingefĂŒhrt â `Cloudflare One Connector: WARP` (Read/Edit) â âGrants write access to Cloudflare Mesh nodes". Das ist
|
||
**nicht** dasselbe wie `Cloudflare Tunnel Write` (nur fĂŒr cloudflared) oder `Cloudflare One Connectors Write`
|
||
(Sammel-Permission, deckt aber laut Doku nicht zuverlÀssig Mesh ab). Verifiziert gegen
|
||
`developers.cloudflare.com/fundamentals/api/reference/permissions/` (aktuelle Tabelle, nicht die Àlteren
|
||
tunnel-spezifischen Doc-Seiten, die noch die alten Namen zeigen). Im Token-Editor unter **Account**-Permissions nach
|
||
**â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" | â
**entschieden: bleibt AUS** â nicht nötig (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 â recherchiert 2026-08-17, Entscheid: bleibt AUS.** Die CF-**Settings-Referenz** fĂŒhrt ihn unter
|
||
> âGlobal device client settings" (also **global**, nicht per Profil â die Mesh-Get-Started-Seite behauptet das
|
||
> Gegenteil, **die Docs widersprechen sich**). VerfĂŒgbar in **allen PlĂ€nen**, alle OS, Client-Mode âTraffic and
|
||
> DNS". **Was er tut:** er lĂ€sst Traffic aus Mesh/WAN **zu den eingebuchten GerĂ€ten hin** â Zugriff auf
|
||
> *Device-IPs*, also die **ClientâClient**-Richtung. **Unser Anwendungsfall ist die andere Richtung**
|
||
> (GerĂ€t â Mesh-Node â `10.40.0.0/16`), und der funktioniert bewiesenermaĂen ohne ihn (§4.5). Die CF-Docs
|
||
> nennen **keinen** MenĂŒpfad, und es gibt **kein API-Feld** (Spec, `devices/settings`-PATCH und Profil-GET
|
||
> gegengeprĂŒft). **Nach User-Vorgabe âim Zweifel ohne Schalter" nicht gesetzt.** Erst dann relevant, wenn
|
||
> Zugriff **auf ein EndgerÀt** statt auf das Netz gebraucht wird.
|
||
|
||
<details><summary>UrsprĂŒngliche Handlungsanweisung (vor der Recherche)</summary>
|
||
|
||
> đŽ **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).
|
||
|
||
</details>
|
||
|
||
### 4.7 Mgmt-ACL via Golden Config auf alle vier GerĂ€te â â
**ERLEDIGT 2026-08-17, `72/72 compliant`**
|
||
|
||
Der `/ip service`-Fix aus §4.5 war zunÀchst nur am Core und **direkt** gesetzt. Nachgezogen als sauberer
|
||
GC-Rollout auf **alle vier** GerÀte.
|
||
|
||
**Der Befund war das Gegenteil der Erwartung.** §4.5 schloss mit âfĂŒr `branch`/`ap1`/`ap2` noch offen â die
|
||
haben eigene `/ip service`-BeschrĂ€nkungen". **Falsch:** sie hatten **gar keine** â `ssh`, `www`, `winbox`,
|
||
`api`, `ftp`, `telnet` alle aktiv und **ohne** Address-BeschrÀnkung. Die dynamischen EintrÀge zeigten sogar
|
||
`REMOTE 100.96.0.1`, waren also lÀngst per Mesh erreichbar. Und **`winbox` war auf allen vier offen**, auch am
|
||
Core. Damit wurde aus dem erwarteten Erreichbarkeits-Fix eine **HĂ€rtung**.
|
||
|
||
| | Sollzustand (einheitlich, im Template) |
|
||
|---|---|
|
||
| `ssh` · `www` · `winbox` · `api` | `address=10.40.0.0/16,100.96.0.0/12` |
|
||
| `ftp` · `telnet` · `api-ssl` | `disabled=yes` |
|
||
|
||
- **Neue Compliance-Feature `ip-service`** (`match_config=/ip service`, `config_type=cli`,
|
||
`config_ordered=false`) â 17â18 Regeln, **68â72 Checks**. Ohne die Regel stĂŒnde die ACL zwar im Template,
|
||
wĂŒrde aber **nie verglichen** â der Rollout wĂ€re nicht durchsetzbar.
|
||
- **Ablauf regelkonform:** `/system backup` auf allen Zielen â `--job mgmt-acl` (Dry-Run) â
|
||
`--apply --no-deploy` â **gestaffelter** Deploy: erst `ap2`, am GerĂ€t gegengeprĂŒft, dann `ap1`/`branch`/`core`
|
||
â GerĂ€te-Gegenprobe â `--refresh-compliance`.
|
||
- **Kein Lockout-Risiko:** der Deploy lĂ€uft von Nautobot (`10.40.20.30`) aus, also aus `10.40.0.0/16` â in jeder
|
||
gesetzten ACL enthalten. RouterOS wendet `address=` ohnehin erst auf **neue** Verbindungen an.
|
||
- â ïž **Scope-Erweiterung, bewusst:** `ftp`/`telnet`/`api-ssl` auf branch/ap1/ap2 **abgeschaltet**. Die
|
||
Alternative wĂ€re gewesen, âtelnet aktiv" als **Sollzustand** in die SoT zu schreiben. Nichts hier nutzt sie
|
||
(der ALLNET-Telnet-Runner ist Archiv, das GerÀt ausgebaut).
|
||
- đ **Schreibweise:** `/ip service set ssh âŠ` mit dem **Dienstnamen**, NICHT `[find name=ssh]` â letzteres
|
||
trifft auch den dynamischen Verbindungs-Eintrag â `failure: this is configured elsewhere`.
|
||
- đ§Ș **Mess-Falle am Rande:** `[/ip service get ⊠address]` in einem `:put`-Ausdruck verketten erzeugt bei
|
||
**zwei** ACL-EintrĂ€gen das **Kreuzprodukt** (16 Zeilen statt 1) â `address` ist eine Liste. Zum PrĂŒfen
|
||
`/ip service print detail` nehmen, nicht String-Verkettung.
|
||
|
||
Job liegt als `mgmt-acl` in `nautobot/gc-configplan.py` (idempotent, wiederholbar).
|
||
|
||
> đ **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").
|
||
2. **âAllow all Cloudflare One traffic to reach enrolled devices" AN** (gleiche Seite).
|
||
3. **Device-Profile âCloudflare Mesh"** anlegen: Match `identity.email == warp_connector@emsenhuber.cloudflareaccess.com`,
|
||
Tunnel-Protokoll = **WireGuard** (`POST /accounts/âŠ/devices/policy`).
|
||
4. **Split-Tunnel-Exclude anpassen** (`PUT /accounts/âŠ/devices/policy/exclude` â â ïž ersetzt die GANZE Liste, erst GET,
|
||
dann editiert zurĂŒckschreiben): `100.64.0.0/10` **raus**, dafĂŒr `100.64.0.0/11` + `100.112.0.0/12` **rein**
|
||
(= 100.64/10 minus 100.96/12 â Mesh-Overlay `100.96.0.0/12` lĂ€uft nun durch WARP statt als âlocal" behandelt zu werden).
|
||
â ïž **Auf BEIDEN Profilen** (Default **und** dem neuen âCloudflare Mesh"-Profil aus Schritt 3 â per-Profile-Endpoint
|
||
`âŠ/devices/policy/{policy_id}/exclude`); animmouse macht das explizit auf beiden.
|
||
5. **ICMP-Proxy â â
bereits AN, KEIN To-Do** (Korrektur 2026-07-17, User): Die offiziellen Mesh-Docs listen âGateway proxy
|
||
mit TCP, UDP, ICMP" als Prerequisite. TCP+UDP sind an (`gateway_proxy_enabled`/`gateway_udp_proxy_enabled`=true);
|
||
**ICMP ist ebenfalls schon angehakt** â **Beweis: `ping` ins FM-Netz `10.101.0.0/24` funktioniert** (ĂŒber den fm-QUIC-Connector).
|
||
Das ICMP-Flag ist nur nicht im public OpenAPI-Spec sichtbar (Dashboard-only), daher hatte ich es fĂ€lschlich als âfehlt" gefĂŒhrt.
|
||
â **Nichts zu klicken.** Dass bf-Ping im Incident 100 % verlor lag NICHT am Flag, sondern daran, dass die macmini-Connectoren
|
||
nach dem http2-Fix QUIC-los sind (cloudflared-ICMP-Proxy braucht QUIC). Mit dem nativen WG-Mesh-Node ist ICMP ohnehin
|
||
nativ (kein Gateway-ICMP-Proxy im Pfad). **Trotzdem: nach dem Scharfschalten Ping gegengeprĂŒft** (§4.5) â falls wider
|
||
Erwarten doch tot, hier zuerst schauen.
|
||
|
||
</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>
|
||
```
|
||
â erzeugt `wgcf-connector-<registration_id>.conf` mit: **PrivateKey**, **Address** (`100.96.x.y/32` **+ eine IPv6** â
|
||
ignorieren, wir bauen v4-only), **DNS** (CF-Resolver â ignorieren, ap1 hat eigenes DNS), **MTU 1420**, Peer-**PublicKey**
|
||
(= CF-Wellknown `bmXOC+F1FxEMF9dyiK2H5/1SUtzH0JuVo51h2wPfgyo=`), **Endpoint** (`162.159.193.x:2408`).
|
||
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 â â
**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
|
||
> existiert: der PrivateKey und die `100.96.x.y`-Adresse aus §4.2.
|
||
|
||
```
|
||
/interface wireguard add name=cf-mesh mtu=1420 private-key="<PrivateKey aus .conf>" comment="TP16.1 Cloudflare Mesh"
|
||
/interface wireguard peers add interface=cf-mesh name=cf-pop \
|
||
public-key="bmXOC+F1FxEMF9dyiK2H5/1SUtzH0JuVo51h2wPfgyo=" \
|
||
endpoint-address=162.159.193.1 endpoint-port=2408 \
|
||
allowed-address=0.0.0.0/0,::/0 persistent-keepalive=25s
|
||
/ip address add address=<100.96.x.y>/32 interface=cf-mesh comment="TP16.1 Mesh-Overlay"
|
||
/ip route add dst-address=100.96.0.0/12 gateway=cf-mesh comment="TP16.1 Mesh"
|
||
```
|
||
|
||
- **Endpoint:** falls die Config `162.159.192.x` liefert â `162.159.193.x` nehmen (Latenz-Tuning laut Guide).
|
||
- **MTU:** 1420 aus dem Guide. Direkter Vergleichswert steht jetzt **auf demselben GerÀt**: `wg-hub` lÀuft mit
|
||
**1412**. Bei Path-MTU-Symptomen (TCP baut auf, groĂe Transfers hĂ€ngen) zuerst auf 1412 angleichen.
|
||
- â
**RĂŒckweg-Routing â erledigt, keine Zusatzarbeit.** `crs326-core` ist der L3-Router **aller** VLANs
|
||
(`vlan10/20/30/40/50/90/99` mit `.1`), RĂŒckverkehr nach `10.40.0.0/16` lĂ€uft also ohne Zusatzroute. Das war
|
||
beim ursprĂŒnglichen CRS326-Retarget die einzige echte Unbekannte.
|
||
- **Namenskollision vermeiden:** auf dem GerĂ€t existiert bereits `wg-hub` (TP10). Das neue Interface heiĂt
|
||
`cf-mesh` â â ïž **Bindestrich in `name=` hat RouterOS beim GC-Push schon einmal abgelehnt** (Memory
|
||
`ref_gc_push_gotchas_routeros`); beim Direkt-Write ĂŒber MikroMCP war das nie ein Problem, aber falls die Zeilen
|
||
spÀter doch durch die GC laufen, ist `cfmesh` der sichere Name.
|
||
- **Firewall:** die `forward`-Kette endet derzeit **ohne Drop** (TP5 steht aus) â der Mesh-Verkehr passiert ohne
|
||
Zutun. â ïž **FĂŒr TP5 vormerken:** sobald deny-by-default greift, braucht es explizit
|
||
`forward accept 100.96.0.0/12 â 10.40.0.0/16`, sonst kappt die Firewall den privaten Zugang. Gehört in die
|
||
TP5-Whitelist, nicht hierher.
|
||
- â
**Governance â Ausnahme #4 erteilt (User, 2026-08-16).** Die frĂŒhere Zeile (âlĂ€uft regulĂ€r ĂŒber Nautobot GC")
|
||
trĂ€gt **nicht mehr**: TP22-Regel 1 schlieĂt jede Sektion mit `<<REDACTED>>` generell vom Push aus, und
|
||
`/interface wireguard` ist genau so eine Sektion â ein Privkey ist ĂŒber GC gar nicht deploybar. Diese vier Zeilen
|
||
dĂŒrfen daher **direkt** (MikroMCP `plan_changes` dryRun â `apply_plan`). **Auflage wie bei Ausnahme #2:** danach
|
||
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
|
||
muss, ist, einen privaten SchlĂŒssel als *Konfiguration* zu behandeln â er ist **GerĂ€te-IdentitĂ€t**, wie ein
|
||
SSH-Hostkey. Die branchenĂŒbliche Regel:
|
||
|
||
> Der private Teil entsteht auf dem GerÀt und verlÀsst es nie. Nur der **öffentliche** Teil geht in die Source of
|
||
> Truth â und wird von dort in die Configs der **Gegenstellen** gerendert.
|
||
|
||
| Was | Klasse | Wo verwaltet |
|
||
|---|---|---|
|
||
| PrivateKey | GerĂ€te-IdentitĂ€t | nur am GerĂ€t â nie in Git, nie in der intended config, nie in einem ConfigPlan |
|
||
| PublicKey | öffentliche Information | Nautobot (Custom Field/Data) â in die Peer-Configs gerendert |
|
||
| `listen-port`, `mtu`, `comment`, Peers, `allowed-address`, Routen, Firewall | Konfiguration | Golden Config, ganz normal |
|
||
|
||
RouterOS unterstĂŒtzt das direkt: `/interface wireguard add` **erzeugt den Privkey selbst**, `print` gibt den
|
||
Pubkey aus. Compliance bleibt trotzdem grĂŒn, weil die `ConfigReplace`-Regel aus TP22 Schritt 0 den Privkey im
|
||
Backup auf **byte-identisch dieselbe** Maske normalisiert, die das Template emittiert.
|
||
|
||
â ïž **Vorbehalt genau hier:** bei Cloudflare Mesh erzeugt **CF** das SchlĂŒsselpaar (§4.2 holt es per `wgcf-connector`).
|
||
Wenn der Flow keinen eigenen Pubkey akzeptiert, fĂ€llt die On-Device-Erzeugung weg â das Prinzip (ânie in Git, nie
|
||
in der intended config") hÀlt trotzdem, der Key wird dann einmalig eingespielt und lebt danach nur am GerÀt.
|
||
|
||
**Stufe 2, falls Secrets doch verwaltet werden mĂŒssen** (mehr GerĂ€te, Rotation, PSKs): `nautobot-secrets-providers`
|
||
nachinstallieren (Vault/AWS SM/Azure KV/1Password; Core kann schon Env-Var + Text-File) und den echten Wert erst
|
||
**bei der ConfigPlan-Erzeugung** einsetzen â gespeicherte intended config behĂ€lt den Platzhalter, der Plan wird
|
||
nach dem Deploy gelöscht. Preis: Klartext liegt transient in Postgres, braucht Retention-Disziplin. Bei vier
|
||
GerĂ€ten und einem Key lohnt das nicht; **das ist ein TP fĂŒr die Zeit nach TP18/TP20.1.**
|
||
*(Nicht verwechseln: `CredentialsNautobotSecrets` + SecretsGroup âRouterOS Nornir" sind schon im Einsatz â das
|
||
sind die **Login**-Credentials fĂŒr Nornir, nicht Secrets *im Config-Inhalt*.)*
|
||
|
||
**Sofort fÀlliger Modellierungs-Nachzug, unabhÀngig vom Mesh:** die WG-Peers `fm` und `dw` stehen heute mit
|
||
hartkodierten `public-key="âŠ"`-Werten im Jinja-Template (`nautobot/mikrotik_routeros.j2`). Public Keys sind Daten,
|
||
keine Templatezeilen â die gehören nach Nautobot und von dort gerendert.
|
||
|
||
### 4.4 Subnetz-Route + vnet-Route umziehen
|
||
- Ziel: die CIDR-Route `10.40.0.0/16` zeigt auf den **neuen Mesh-Node** statt auf `bf-pve`.
|
||
- **Weg A (zuerst versuchen):** `PATCH /accounts/âŠ/teamnet/routes/5546dcb6⊠{tunnel_id: <warp_connector_id>}` â
|
||
gleiche `teamnet/routes`-API wie cloudflared, per CF-Docs auch fĂŒr Mesh-Nodes gĂŒltig.
|
||
- â ïž **Neu-Fund vnet-Gotcha:** CF-Docs sagen â**Virtual networks are only supported for cloudflared tunnels**" â
|
||
unsere Route hĂ€ngt am vnet `1480b545âŠ` (`vnetemsenhuber`, ist aber das **default**-vnet des Accounts). Möglich,
|
||
dass der PATCH auf einen `warp_connector`-Tunnel deshalb mit 4xx abgelehnt wird.
|
||
**Weg B (Fallback):** `DELETE` der alten Route `5546dcb6âŠ` + `POST /teamnet/routes {network:"10.40.0.0/16",
|
||
tunnel_id:<mesh_node_id>}` **ohne** vnet-Angabe (landet im default). Kurze LĂŒcke (Sekunden) dazwischen ist ok â
|
||
Reihenfolge DELETEâPOST zwingend (CIDR-Kollision verhindert POST-vor-DELETE).
|
||
- **Rollback jederzeit:** PATCH (bzw. DELETE+POST) zurĂŒck auf `f7fdf3a6âŠ` (bf-pve) â cloudflared/bf-pve bleibt die
|
||
ganze Zeit bestehen. **Wichtig fĂŒrs Remote-Arbeiten:** alle CF-API-Writes laufen ĂŒber die öffentliche API
|
||
(api.cloudflare.com), NICHT ĂŒber WARP â Rollback funktioniert auch, wenn der private Pfad gerade tot ist.
|
||
|
||
### 4.5 Verifikation â â
**BESTANDEN 2026-08-17** (MacBook am iPhone-Hotspot, WARP connected)
|
||
|
||
**Ping â der eigentliche Zweck des TPs. Vorher 100 % Loss, jetzt:**
|
||
|
||
| Ziel | VLAN | Loss | avg RTT |
|
||
|---|---|---|---|
|
||
| `10.40.10.1` | 10 | **0 %** | 47 ms |
|
||
| `10.40.20.105` (HA) | 20 | **0 %** | 56 ms |
|
||
| `10.40.99.12` (ap2) | 99 | **0 %** | 57 ms |
|
||
| `10.40.20.10` (NAS) | 20 | **0 %** | 63 ms |
|
||
| `10.40.99.1` (core) | 99 | **0 %** | 58 ms |
|
||
|
||
**TCP-Gegenprobe (echter Datenfluss, nicht nur Connect):** `https://10.40.20.100:8006` â 200 ·
|
||
`http://10.40.20.30:8080` â 302 · `ssh macmini` â ok. **FQDN-Smoke** (gitea/hass/pve/nautobot/vw ĂŒber
|
||
`*.emsenhuber.net`): 200/200/302/302/200 in 0,2â0,3 s â **der cloudflared-Public-Teil blieb unberĂŒhrt.**
|
||
*(`10.40.20.10:5000/5001` antwortet nicht â die DSM-Web-Ports lauschen dort schlicht nicht; SSH und 443 auf
|
||
demselben Host sind offen. Kein Mesh-Befund.)*
|
||
|
||
> đŽđŽ **DIE FALLE DIESES TPs â `/ip service` sperrt das Router-Management aus dem Mesh aus.**
|
||
>
|
||
> Unmittelbar nach dem WARP-Connect war **`crs326-core` mgmt-seitig tot**: MikroMCP brach mit
|
||
> `Connection lost before handshake` ab, SSH mit `kex_exchange_identification: Connection reset`, REST mit
|
||
> **HTTP 502** â **wĂ€hrend Ping zu genau derselben IP verlustfrei lief** und alle Hosts *hinter* dem Core
|
||
> (pve, Nautobot, macmini) normal antworteten.
|
||
>
|
||
> **Ursache:** auf dem Core steht `/ip service set ssh,www address=10.40.0.0/16`. Der Mesh-Client kommt aus
|
||
> **`100.96.0.0/12`** und fĂ€llt aus der ACL. ICMP kennt keine Service-ACL â geht. Und `nc -z` meldete
|
||
> âoffen", weil der **CF-Gateway-Proxy** den TCP-Handshake terminiert, bevor das Origin ĂŒberhaupt antwortet â
|
||
> ein TCP-Connect ist ĂŒber WARP also **kein** Reachability-Beweis.
|
||
>
|
||
> **Fix:** `/ip service set [find name=ssh] address=10.40.0.0/16,100.96.0.0/12` (analog `www`).
|
||
> Danach SSH und REST ĂŒber den Mesh sauber. **Merkregel: wer per Mesh ans Netz kommt, ist noch lange nicht
|
||
> am Router.** Jede Mgmt-ACL, die auf `10.40.0.0/16` steht, muss die Mesh-Range mitnehmen â
|
||
> fĂŒr `crs326-branch`/`ap1`/`ap2` ist das noch **offen** (die haben eigene `/ip service`-BeschrĂ€nkungen).
|
||
>
|
||
> â ïž Zwei Fehlspuren, die ich unterwegs verfolgt habe und die man sich sparen kann: (1) **MTU** â groĂe Pings
|
||
> ab ~1350 B scheitern, das ist aber das **WARP-Client-Interface** (`utun` MTU 1380), nicht `cf-mesh`;
|
||
> normaler TCP-Verkehr ist davon nicht betroffen. (2) **SSH-Session-Erschöpfung** â naheliegend bei
|
||
> `Connection reset`, war es aber nicht. Der Test, der es entschied: **Banner-Grab vom macmini aus**
|
||
> (`nc 10.40.99.1 22` â `SSH-2.0-ROSSSH`) â von innen gesund, also Pfad/ACL statt GerĂ€t.
|
||
>
|
||
> âčïž Nebenbefund beim Setzen: `/ip service set [find name=ssh] âŠ` trifft **auch den dynamischen
|
||
> Verbindungs-Eintrag** (`D c ssh ⊠local 10.40.99.1`) und quittiert mit `failure: this is configured
|
||
> elsewhere`. **Harmlos** â der statische Eintrag wird trotzdem gesetzt. Nicht als Fehlschlag werten.
|
||
|
||
### 4.6 Auflage Ausnahme #4 â â
**ERLEDIGT 2026-08-17: Ist-Stand ist intended config, 68/68 compliant**
|
||
Ablauf: `--refresh-compliance` zeigte zuerst **65/68** mit drei `extra`-Drifts (interface-wireguard,
|
||
ip-address, ip-route) â exakt die Mesh-Zeilen. Die Zeilen **byte-genau aus dem Nautobot-Backup** (nicht aus
|
||
dem Runbook!) ins Jinja-Template ĂŒbernommen, ins GC-Repo `bf-golden-config` gepusht, Repo-Sync, erneut
|
||
compliance: **68/68, keine Drifts.**
|
||
- Der Privkey bleibt drauĂen: das Template emittiert `private-key="<<REDACTED>>"` â byte-identisch zur
|
||
`ConfigReplace`-Maske aus TP22 Schritt 0, genau wie bei `wg-hub`. Secret-Gegenprobe vor jedem Push gelaufen.
|
||
- â ïž **Gotcha beim Push:** Nautobot schreibt Backups *und* intended configs in **dasselbe** Repo â der zweite
|
||
Push wurde `rejected (fetch first)`, weil die Compliance-LĂ€ufe dazwischen committen. `git pull --rebase`
|
||
vor jedem Push einplanen.
|
||
- `/ip service` steht **nicht** im Template â die ACL-Erweiterung erzeugt keine Drift, ist damit aber auch
|
||
**nicht** in der SoT abgebildet. Bewusst so belassen; gehört zu TP5, wenn die Mgmt-Ebene modelliert wird.
|
||
|
||
<details><summary>UrsprĂŒngliche Abnahme-Kriterien</summary>
|
||
|
||
### 4.5 Verifikation (Abnahme)
|
||
- MacBook, WARP **connected**: `ping 10.40.20.105`, `ping 10.40.10.1`, `ping 10.40.99.12` â **verlustfrei**
|
||
(Regressions-Gegenprobe zu heute: fm 36 % / bf 100 %).
|
||
- TCP-Gegenprobe inkl. NAS-macvlan-IP direkt: `ssh 10.40.20.167`, `https://10.40.20.100:8006`, `10.40.20.157:3000`
|
||
(gitea) mehrfach â Beweis âkeine Blindheit".
|
||
- FQDN-Smoke (Stichprobe gitea/hass/pve ĂŒber `*.emsenhuber.net`) â der cloudflared-Public-Teil (3-Tunnel-HA) blieb unberĂŒhrt.
|
||
|
||
</details>
|
||
|
||
## 5. Danach (Cleanup, teils ins âvertagt"-GesprĂ€ch)
|
||
- Nach Mesh-Beweis: `warp-routing` auf bf-nas/bf-pve/bf-mm ggf. auf `false` (Hygiene â Public-Tunnel bedienen keine
|
||
privaten Netze mehr). CF-vnet-Route-Historie bereinigen.
|
||
- **Vertagt (User âmĂŒssen wir noch reden, hat Zeit"):** 4 tote Tunnel (TeilzeitCharlie/coolify/johnny2/openclaw),
|
||
Ghost-Connector-Session bf-pve (arm64-Leiche vom 12.07.), `gateway-dw`-CNAME.
|
||
|
||
## 6. Risiken / Fallbacks
|
||
- Einziger Eingriff mit Nutzer-Impact = vnet-Route-Umzug â Rollback = 1 PATCH zurĂŒck auf bf-pve.
|
||
- CF-Prerequisites sind account-weit (Unique-IP-ReIP, Split-Tunnel) â 1Ă kurzer WARP-Reconnect; alle reversibel.
|
||
- Plan-Gate: wenn `warp_connector`-Create scheitert â LXC-auf-pve-WARP-Connector als Fallback (TUN-Passthrough
|
||
`c 10:200 rwm`, `warp-cli connector new`, ap1-Static-Route `100.96.0.0/12`âLXC).
|
||
- axÂł/ZeroTier/Tailscale = separate Eval-FuĂnoten, nicht Teil dieses Fixes.
|
||
|
||
---
|
||
|
||
## Nachtrag 2026-08-25 â âConnector als RouterOS-Container â" galt dem TUN-Bedarf, nicht jedem Container
|
||
|
||
§2 schlieĂt âConnector als RouterOS-Container" aus, weil **RouterOS-7-Container kein `/dev/net/tun`
|
||
durchreichen** und der WARP-Connector-Daemon ein TUN-Device braucht. **Das stimmt weiterhin â fĂŒr den
|
||
WARP-Connector.**
|
||
|
||
đŽ **Es wurde damals aber nicht getrennt, und die Verallgemeinerung hat sich festgesetzt:**
|
||
**`cloudflared` braucht kein TUN.** Es ist ein Userspace-HTTP/QUIC-Proxy und lÀuft in einem
|
||
RouterOS-Container problemlos â auf arm64 oder x86, `container`-Paket und `device-mode` vorausgesetzt.
|
||
|
||
**Live gemessen 2026-08-25:** ap1/ap2 sind **arm64** mit **95 MB freiem Flash** und **690 MB freiem RAM**
|
||
â genug fĂŒr einen Connector. `crs326-core` ist **arm 32-bit mit 2,9 MB frei von 16 MB** und kommt fĂŒr
|
||
Container **nie** in Frage.
|
||
|
||
â Die Zeile âverletzt *Router = einziger SPOF, keine AbhĂ€ngigkeit zu anderen Rechnern*" trug fĂŒr den
|
||
privaten Strang â fĂŒr den **öffentlichen** hat sie nie jemand geprĂŒft. Genau das holt **TP31** nach.
|