Files
bf-infra/CLAUDE.md
Christoph Emsenhuber bb2c87c68e Compliance 68/68 + TP24 (USV) ausgeloest + Doku auf den Stand nach dem Core-Cutover
Zwei Straenge, die sich dieselben Dateien teilen — deshalb ein Commit.

1) COMPLIANCE-DRIFTS BESEITIGT (User: "beseitige autonom alle") -> 68/68, 0 Drifts

Entfernt wurden die 4 verbliebenen `extra`-Drifts (der fuenfte, core 10.40.41.211,
war schon ueber TP19-vlan1-core-address gefallen):
- ap1 + ap2: Werks-defconf `/ip dns static router.lan -> 192.168.88.1`. Auf beiden
  APs der einzige statische Eintrag, die IP existiert im Netz nicht. Der Core hat
  sein eigenes, korrektes router.lan -> 10.40.99.1 (im Template, compliant).
- crs326-branch: Bring-up-Rest SVI vlan10 + 10.40.10.2, Adresse zuerst.

Richtung bewusst "am Geraet entfernen" statt "ins Template aufnehmen" — genau so
steht es seit 2026-08-13 im Switch-Zweig des Templates. Der frueher notierte
Vorbehalt "potenzielle Rettungspfade" ist per User-Entscheid aufgehoben; der
Mgmt-Fallback aus VLAN10 auf dem branch entfaellt damit (Rueckweg = MAC-Winbox am
selben Draht).

Weg: 3 manuelle GC-ConfigPlans, kein Direkt-Write. Vorher /system backup je Geraet.
Deploy gestaffelt — erst die APs, am Geraet gegengeprueft, dann branch.

Verifikation am GERAET, nicht am Job: DNS-Statics total=0 bei unveraenderten 28
bzw. 3 WLAN-Clients; branch nur noch vlan99 + 10.40.99.2/24; Ping vom Core 4/4.
Entscheidende Gegenprobe: /interface bridge vlan/export byte-identisch — `bridge`
steht dort statisch als tagged-Member von VLAN10, das Entfernen des SVI hat also
weder Traffic-Wirkung noch neuen Drift. Danach Backup -> Intended -> Compliance,
alle 4 Geraete mit frischem Success-Datum.

Neue API-Falle, die erklaert warum es bisher kein Skript gab:
POST /plugins/golden-config/config-plan/ ist 405 — das ViewSet ist read-only.
ConfigPlans entstehen nur ueber den Job "Generate Config Plans" (plan_type=manual
+ commands-TextVar). plan_type=missing erzeugt ausserdem nur add-Zeilen, also muss
alles Entfernende zwangslaeufig ein manueller Plan sein.

Neu: nautobot/gc-configplan.py — loest Device-UUIDs einzeln per Name auf und
assertet plan.device UND config_set gegen das Ziel (die alphabetische
Sortier-Falle aus TP21.1 kann damit nicht wiederkommen), verweigert config_sets
mit <<REDACTED>> (Regel 1) und print-Zeilen, kann gestaffelt deployen
(--deploy-ids) und kapselt Backup -> Intended -> Compliance (--refresh-compliance).
Dry-Run ist Default.

2) TP16.1: GATE OFFEN, Runbook ausfuehrungsreif, Governance-Ausnahme #4

Die Bedingung "gated bis TP21 den CRS326 abdeckt" ist seit der Adoption am
2026-08-13 erfuellt. §3 neu gemessen, §4.3 von Platzhalter auf echte Werte.
Die letzte inhaltliche Unbekannte hat sich erledigt: "Rueckweg-Routing TBD" —
der Core IST L3-Gateway aller VLANs, es braucht keine Zusatzroute. wg-hub liegt
auf demselben Geraet und ist damit direktes Vorbild statt fernes Muster.

Klarstellung, weil leicht zu verwechseln: das Mesh ersetzt die Tunnel NICHT. Es
loest nur den privaten Zugang (10.40.0.0/16 per IP, inkl. ICMP); die oeffentlichen
FQDNs bleiben auf cloudflared. Relevant dabei: die Route 10.40.0.0/16 zeigt auf
bf-pve — und der faehrt derzeit nur einen Connector.

Ausnahme #4 (User 2026-08-16): die WG-Zeilen des Mesh-Bring-ups auf crs326-core
duerfen direkt gesetzt werden. Grund ist strukturell, nicht bequem — TP22-Regel 1
schliesst jede <<REDACTED>>-Sektion vom Push aus, ein Privkey ist ueber Golden
Config gar nicht deploybar. Auflage: Backup vorher, intended config danach zurueck
nach Nautobot. Scope: nur dieser Bring-up.

Damit das ein einmaliger Bootstrap bleibt, ist das Secret-Handling-Design
dokumentiert: ein privater Schluessel ist Geraete-Identitaet, keine Konfiguration
(wie ein SSH-Hostkey). Der private Teil entsteht am Geraet und geht nie weg, nur
der oeffentliche kommt in die SoT und wird in die Peer-Configs gerendert.
Stufe 2 (nautobot-secrets-providers + Vault) lohnt bei 4 Geraeten und einem Key
nicht. Nebenbefund: die WG-Peers fm/dw stehen mit hartkodierten public-keys im
Jinja-Template — Public Keys sind Daten, keine Templatezeilen.

3) TP24 — USV aus TP15 herausgeloest (User-Entscheid)

Die DC-USV war der letzte offene Rest in TP15 und hat mit Switching/Routing
sachlich nichts zu tun (eigene Einkaufs-, Verkabelungs- und Elektrik-Logik).
TP15 ist damit inhaltlich zu. TP24 traegt jetzt 48V-Bus, MeanWell/LiFePO4,
Laufzeiten, DC-Eingangs-Tabelle und die 5 offenen Entscheidungen — darunter neu
die Standortfrage, die sich durch den Core-Umzug ins UG neu stellt.

4) DOKU-AUFRAEUM-SESSION A-E abgearbeitet

- Ist-Stand-Block neu geschrieben, live gegen die Geraete geprueft. Alte Fassung
  als ausklappbare Historie, ⚠️-Provisorium entfernt.
- Reihenfolge-Abschnitt auf den echten Rest-Pfad TP5 -> TP6 eingedampft (Punkt 3
  sagte noch "Jetzt: Omada-PVID-Fix").
- Stale ap1-als-Router-Aussagen in TP3/TP4/TP15/TP16.1/TP21/TP-R korrigiert —
  fortgeschrieben, nicht ueberschrieben.
- CLAUDE.md: Mac mini .41.167 -> .20.167 (war stale, live per ARP bestaetigt),
  branch-Uplink "sw1 GE8" -> "core ether8", ALLNET-/Omada-Gotchas als Historie.
- switch/ als Archiv gekennzeichnet (Geraet ausgebaut, Runner nicht ausfuehrbar).
- omada-mcp + CF-Ingress live gegengeprueft: beides sauber, Punkt abgehakt.

Nebenbefund, eingetragen aber nicht angefasst: das CF-Tunnel-HA ist degradiert
(bf-nas und bf-pve mit je nur einem Connector), und vier tote Alt-Tunnel tragen
VLAN1-Origins — darunter die Aufloesung des "unidentifizierten VLAN1-Geraets
.41.133" aus TP19 (es ist das coolify-Origin).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-16 19:28:50 +02:00

13 KiB
Raw Blame History

BF-Netzwerk — Projekt-Kontext (auto-read)

Standort BF: VLAN-segmentiertes Heimnetz auf MikroTik/RouterOS. Ziel: CAKE/QoS gegen Bufferbloat, DNS/DHCP-Ablösung, WLAN via Standalone-APs (kein CAPsMAN), Firewall Least-Privilege, Multi-Site VPN.

Für jede TP-Session: zuerst docs/teilprojekte.md lesen — enthält kanonischen Stand, Scope, Abhängigkeiten und Reihenfolge aller Teilprojekte. Kein anderer Kontext nötig.


VLAN-Modell (kanonisch)

VLAN Name Subnetz Zweck
10 MAIN 10.40.10.0/24 Trusted (Handy/Laptop)
20 INFRA 10.40.20.0/24 NAS/VMs/Docker/HA
30 IOT 10.40.30.0/24 Smart-Home
40 MEDIA 10.40.40.0/24 Sonos/AppleTV/TV/Cast
50 UNTRUSTED 10.40.50.0/24 Konsole/Low-Trust
90 GUEST 10.40.90.0/24 nur Internet
99 MGMT 10.40.99.0/24 Switch/AP/Hypervisor-Mgmt
100 WAN (Arris-Transfer) zum Arris-Kabelmodem (Liwest, Public-IP)

GW je VLAN = .1 (crs326-core L3) · Mgmt VLAN99: core .99.1, branch .99.2, ap1 .99.11, ap2 .99.12


Hardware & Zugang

Gerät IP Zugang
ALLNET Core-Switch (sw1) — ❌ außer Betrieb (2026-08-08) — durch crs326-core (L3-Router + Core-Switch, Technik UG) ersetzt; physisch abgelöst. (Telnet-Runner switch/ = nur noch historisch.)
Omada Access-Switch (sw2) — ❌ abgebaut 2026-07-23 (TP15 Branch-Tausch) — durch crs326-branch in Technik OG ersetzt, physisch entfernt
crs326-branch (CRS326, Technik OG) 10.40.99.2 (VLAN99; temp VLAN10 .10.2) · Bootstrap Rev4 2026-08-08 RouterOS 7.19.5 · admin/~/.secrets (CRS326_BRANCH_*) · REST http://10.40.99.2/rest · MikroMCP crs326-branch ✅ live (2026-08-16 verifiziert) · TP15 ✅: ersetzt sw2 (L2-Switch), volle Portbelegung (ether1 Uplink-Trunk, 2/8 NAS, 3 Drucker, 4 Dock, 5/6 Sonos, 7 macmini, 24 ap2) · sw-id RGZJ-UK0T, MAC 04:F4:1C:B4:15:58
crs326-core (CRS326, Technik UG) 10.40.99.1 (VLAN99-SVI = L3-GW; same-subnet-Fallback 10.40.10.1) · Identity crs326-core RouterOS 7.19.5 · admin/~/.secrets (CRS326_CORE_*) · MikroMCP routerId crs326-core ✅ live (2026-08-16 verifiziert) · TP15/TP21.1 ✅ 2026-08-08: PRODUKTIVER L3-Router (ersetzt ap1) — Routing/DHCP (7 Server + 54 Leases)/DNS (plain 1.1.1.1, DoH-Cloudflare-TODO)/NAT/WG-Hub (fm+dw live); WAN vlan100=Liwest 90.146.33.177 · sw-id 4W04-URHT, MAC 04:F4:1C:B4:17:76
hAP ax² #1 (ap1) 10.40.99.11 (VLAN99) · Identity ap1 RouterOS 7.23.2 · admin/~/.secrets (ROUTER_AP1_*) · REST http://10.40.99.11/rest · MikroMCP ap1 ✅ live · TP3-Rebuild ✅ 2026-08-08: reiner Standalone-AP, KEIN CAPsMAN — Uplink ether1 (PoE-Port, poe-out=off) an crs326-core ether15; 6 SSIDs dirtyvader-main/-infra/-iot/-media/-untrusted/-guest, ch36/ch1; jede SSID mit datapath (TP3.1-Leck gefixt) · MAC D0:EA:11:4D:40:E0 · Config-Referenz routeros/.secrets/ap1-prov-base.rsc
hAP ax² #2 (ap2) 10.40.99.12 (VLAN99) · Identity ap2 RouterOS 7.23.2 · admin/~/.secrets (ROUTER_AP2_*) · REST http://10.40.99.12/rest · MikroMCP ap2 · TP3-Rebuild ✅ 2026-08-08: reiner Standalone-AP — Uplink ether1 (PoE) an crs326-branch ether24; identisch zu ap1, ch149/ch11 · MAC D0:EA:11:4D:40:3A · Config routeros/.secrets/ap2-prov-base.rsc
🔑 Einheitliches Admin-PW (2026-08-08) alle 4 MikroTik (core/branch/ap1/ap2) user admin, gleiches PW (~/.secrets/credentials.env → ROUTER_*_PASS/CRS326_*_PASS; „Überlebensversicherung", User-Vorgabe). Werks-Defaults ap1/ap2 damit obsolet.
NAS (nas-bf, DS923) 10.40.20.10 SSH adm.christoph@10.40.20.10 (kein PW nötig) · Docker (Portainer endpointId=14)
platform-pg (LXC 105, pve) 10.40.20.20 SSH via pve (pct exec 105 --) · TP20 ✅ 2026-07-16: PG16, DB nautobot, Creds postgres/.secrets
Nautobot (Portainer-Stack, NAS) 10.40.20.30 Portainer ep14, Stack Id 203 · TP21 ✅ 2026-07-16: ghcr.io/nautobot/nautobot:3.1.7, DB=platform-pg, Creds in docs/nas-vlan20/stacks/210-nautobot.yml (gitignored) · TP22 ✅ 2026-08-13: Golden-Config-App + Device-Adoption DURCH — alle 4 MikroTik adoptiert, Deploy-Pipeline scharf (Image 3.1.7-gc9), 68/68 Compliance-Checks grün / 0 Drifts (2026-08-16)
Omada-Controller — ❌ entfernt 2026-07-16 (User hat den Container gelöscht — overkill für 1 Switch auf der Abschussliste, s. TP2.1/TP15)
omada-mcp — ❌ entfernt 2026-07-16 — mit dem Controller gelöscht. ✅ Aufräumen erledigt/gegenstandslos (geprüft 2026-08-16): nicht mehr in mcpServers registriert (nur noch als „disabled" in ein paar Projekt-Scopes = harmloser Merkposten), und kein omada-Hostname mehr im CF-Ingress
pve-mcp 10.40.20.173 StreamableHTTP http://10.40.20.173:3000/ (Root-Pfad, NICHT /sse) · NAS-Stack ep14 (=nas-bf .20.10, NICHT LXC .126!) id 202 (vlan20-only, TP14.1 2026-07-10) · mcp-pve v0.6.1 (Upgrade 2026-07-10: Single-Session-Bug 0.4.8 „Server already initialized" gefixt, TP14.2a) · ~/.claude.json ✓
Proxmox (pve) 10.40.20.100 ssh root@10.40.20.100 (SSH-Key ✓) · TP14 2026-07-13: Host-Mgmt VLAN1→VLAN20 (vmbr0.20 + Default-GW-Flip); .41.100 bleibt interim ohne Route
Docker-LXC (auf pve) 10.40.20.126 Portainer CE 2.40.0 (https://10.40.20.126:9443) · TP14.2 2026-07-10: LXC 400 net0 tag=20/.20.126 (iface heißt jetzt veth20, NICHT eth0); Docker-Netz vlan20=ipvlan parent veth20; adguard_bf1 .20.16, adguard_fm2 .20.17
Mac mini 10.40.20.167 (VLAN20) ssh macmini · ⚠️ die früher hier stehende 10.40.41.167 war stale (VLAN1) — live korrigiert 2026-08-16 (ARP reachable auf vlan20)
Arris-Kabelmodem (Bridge-Mode, keine Mgmt-IP im BF-LAN) Liwest-Edge · speist crs326-core vlan100 (VLAN100-Transfer, WAN-IP 90.146.33.177) — seit Core-Cutover 2026-08-08, davor via sw1 gi16 → ap1 · FritzBox 6660 seit 2026-07-01 komplett ausgebaut (Liwest-Tausch, kein Zurück); Telefonie nicht weitergeführt

Tooling

  • MikroTik (core/branch/ap1/ap2): MikroMCP-Server live → mcp__mikromcp__*-Tools (routerId crs326-core/crs326-branch/ap1/ap2). Reads immer safe; Writes mit dryRun:true previewen, dann apply_plan. Passwort setzen via manage_user set-password (/user set* ist per Deny-Policy blockiert). bridge/vlan/set nur auf [find … and !dynamic].
  • ALLNET-Switch (sw1): ❌ Gerät ausgebaut 2026-08-08 → der Telnet-Runner unter switch/ ist Archiv, nicht mehr ausführbar (kein Endpunkt). Siehe switch/README.md. Nicht mehr als Werkzeug anbieten.
  • Omada-Switch (sw2): ❌ abgebaut 2026-07-23 (TP15, durch crs326-branch ersetzt). Controller + omada-mcp komplett gelöscht — Omada spielt keine Rolle mehr, nie wieder aufgreifen (User-Entscheid 2026-07-22). Aufräum-Reste ✅ geprüft 2026-08-16 (s. Tabelle oben).
  • Nautobot Golden Config (= der einzige legitime Config-Weg für Netzgeräte): nautobot/gc-configplan.py (Token = NAUTOBOT_SUPERUSER_API_TOKEN aus docs/nas-vlan20/stacks/210-nautobot.yml, gitignored). --job <name> legt manuelle Pläne an (Dry-Run default), --deploy-ids … deployt gestaffelt, --refresh-compliance fährt Backup → Intended → Compliance in der einzig richtigen Reihenfolge. ⚠️ POST /api/plugins/golden-config/config-plan/ ist 405 — das ViewSet ist read-only. ConfigPlans entstehen nur über den Job Generate Config Plans (plan_type=manual + commands-TextVar).
  • Docker-Management: Portainer API https://10.40.20.126:9443, Key in mcp/portainer/.env. Ablösung durch Komodo (native MCP) geplant.

Kritische Gotchas

  • 📜 ALLNET-Gotchas (1 Telnet-VTY, save nicht vergessen) — gegenstandslos seit 2026-08-08 (Gerät ausgebaut). Nur noch historisch relevant, s. switch/README.md.
  • hAP ax² hat 128 MB Flash, kein USB → Container NICHT auf dem Router; Container laufen auf NAS/pve.
  • VLAN20-Docker-Hosts: Host-DNS nach dem Umzug prüfen (2026-07-10, TP14.2a): NAS + pve-LXC zeigten /etc/resolv.conf noch auf totes .41.254 → docker pull ghcr scheitert (EAI_AGAIN, aber Egress ok!). Fix = .20.1: LXC pct set 400 --nameserver 10.40.20.1; Synology-Falle: DSM-„Allgemein"-DNS ≠ was dockerd liest — Interface zieht DNS per DHCP → Fix an der Netzwerkschnittstelle „DNS manuell". Laufende Container frieren den 127.0.0.11-Upstream zum Erstellzeitpunkt ein (Recreate nötig). Merkregel: docker-pull-hängt + dns.lookup EAI_AGAIN aber TCP zu ghcr-IP:443 ok = toter Resolver, nicht Egress.
  • 📜 ALLNET VLAN-DB (TP1) — historisch. Die VLAN-Semantik gilt weiter (40=MEDIA, 50=UNTRUSTED), die Portangaben (GE1/GE2/GE8) beziehen sich auf ein ausgebautes Gerät.
  • ap2 hängt an crs326-branch ether24 (Trunk, native VLAN1 + tagged 10-99); branch-Uplink ether1 → crs326-core ether8 (korrigiert 2026-08-16 — die frühere Angabe „→ sw1 GE8" stammt aus der Zeit vor dem Core-Tausch; MAC-hart belegt in TP22 Schritt 5).
  • Mesh = NEIN (beide APs haben wired Trunk-Uplink → Loop-Risiko).
  • Beide APs = Standalone mit vlan-filtering=yes, KEIN CAPsMAN (TP3-Rebuild ✅ 2026-08-08): datapath.vlan-id landet nur mit vlan-filtering auf der Leitung. Nur Master-Radios wifi1/wifi2 sind Bridge-Ports (Slave-VAPs forwarden darüber) → wifi1/wifi2 müssen tagged-Member je Client-VLAN sein. Uplink=ether1 (PoE), VLAN1 untagged=Fallback. Jede SSID-config braucht datapath (sonst egress ungetaggt in VLAN1 = das alte TP3.1-Leck). Falle bei Neu-Provisionierung: Werks-Inline-Overrides auf wifi1/wifi2 (configuration.ssid=MikroTik-*, security.*) überschreiben das verlinkte Profil → nach /import mit !configuration.ssid !security.* leeren. Configs routeros/.secrets/ap{1,2}-prov-base.rsc.
  • mgmt-VLAN-Wechsel am Switch = Lockout-Risiko: VLAN muss existieren + Port muss es tragen, in einem Schritt.
  • 📜 Omada ES208G = Easy Managed — gegenstandslos (Gerät abgebaut 2026-07-23, Controller gelöscht).
  • L3-Router = crs326-core (TP21.1 ✅ 2026-08-08, ersetzt ap1). Bridge vlan-filtering=yes; VLAN-SVIs .1 je VLAN mit DHCP (7 Server / 54 Leases); DNS aktuell plain 1.1.1.1 (DoH-Cloudflare-Gateway-TODO, core hat kein CA). ap1/ap2 sind NUR noch APs — kein DHCP/DNS/NAT/Routing/WG dort. (Die frühere „TP4: ap1 ist L3-Router"-Zeile ist überholt.)
  • ✅✅ Edge-Cutover (2026-07-01; Router-Umzug 2026-08-08): FritzBox ausgebaut, Arris im Bridge-Mode. Liwest hat die FB6660 dauerhaft gegen ein Arris getauscht (physisch weg). WAN terminiert auf crs326-core vlan100 (VLAN100-Transfer), core zieht die öffentliche Liwest-IP 90.146.33.177 → kein Double-NAT. core = Public-Edge + WG-Hub (fm/dw live), NICHT mehr ap1. Telefonie nicht weitergeführt. Runbook routeros/wan-cutover-runbook.md (ap1-Teile historisch).
  • hAP device-mode=home (ap1/ap2): scheduler + fetch blockiert (not allowed by device-mode) → AP-Provisionierung idempotent ohne Scheduler. [/ping] gibt nil in 7.23. REST je AP http://10.40.99.11|12/rest (Creds = ROUTER_AP{1,2} in ~/.claude.json). Der L3-Router crs326-core ist KEIN device-mode=home → dort gehen scheduler/fetch (z.B. DDNS-Updater).
  • Erstzugriff Werks-hAP am CRS-Fabric: Uplink ether1 = Werks-WAN → 192.168.88.1 (LAN) darüber NICHT erreichbar. Weg: Gerät auf LAN-Port (ether2) patchen ODER Core-Temp-Pfad 192.168.88.2/24 auf core-bridge + srcnat masq 192.168.88.0/24, dann scp+/import (danach Temp-Pfad + stale ARP .88.1 entfernen). Winbox-Neighbors zeigt die APs NICHT (MNDP pro-VLAN, Mgmt auf vlan99) — kein L2-Fehler.
  • P750W (Brother, VLAN30) läuft auf dirtyvader-iot (User-bestätigt 2026-08-08) — kein Access-List-Pin nötig; die alte „nur am co-located L3-GW-AP erreichbar"-Logik ist mit L3-GW auf dem Core hinfällig. Coverage-Kanten/Terrasse grenzwertig (−76..−89 dBm); TX am AT-Max (18/15 dBm); echter Fix = Platzierung. SSoT docs/wifi-p750w-coverage-and-map.md. ⚠️ Power-Save ist KEIN Thema dieses Netzes — die früher hier stehende Merkregel „DHCP-geht-aber-Ping-nicht = ARP/Power-Save" war eine Fehldiagnose (2026-08-13 korrigiert: der Drucker war schlicht ausgeschaltet, das Ping-Symptom war WARP, s.u.). Nicht wieder einführen.
  • Ping auf JEDE lokale IP tot, aber Web/App/Print (TCP) geht überall = WARP-Client lokal versehentlich noch aktiv (2026-08-13 live beobachtet, BF vor Ort): cloudflared/WARP ist QUIC-Proxy, kann kein ICMP, reicht TCP aber durch — auch wenn man physisch im BF-LAN steht, nimmt der Client bei aktivem WARP trotzdem den Tunnel-Umweg. Fix: WARP trennen, kein Router-Eingriff nötig. Vor jeder Firewall-/Mangle-/VLAN-Suche zuerst prüfen, wenn das Symptom „Ping auf ALLES tot, TCP geht" lautet — das ist ein Client-, kein Netzproblem. Strukturell schließt TP16.1 (natives WireGuard-CF-Mesh auf crs326-core statt cloudflared-QUIC) genau diese ICMP-Lücke. Memory ref_warp_local_icmp_trap.