TP15: Core-Swap vorbereitet (staged L3-Config + WG-Hub-Fund)

- routeros/tp15-core-l3-staged.rsc: ap1s Live-L3-Config 1:1 als staged
  Config (alles Betriebsumlenkende disabled=yes, Cutover-Enable in einem
  Rutsch). Reservierungen + WG-Privkey bewusst erst im Fenster maschinell
  von ap1 geholt statt abgetippt.
- Fund/Luecke geschlossen: WG-Hub (TP10 FM/DW-VPN) haengt an ap1s
  Public-Edge, im Handoff uebersehen -> migriert im selben Fenster mit.
- Fenster-Start-Entscheide: Governance = frische Direkt-Ausnahme #3
  (REST/MikroMCP, danach intended->Nautobot); Rettungspfad iPhone-Hotspot.
- Prep-Gotchas dokumentiert: MikroMCP kann core noch nicht schreiben
  (ENV nicht geladen), Mgmt-.99.11 tot (nur .41.211), WG-Keypair-Transfer,
  Public-IP-Wechsel am WAN, vlan99 .1-vs-.11-Reconcile, VLAN1-Teardown.
- teilprojekte.md TP15 fortgeschrieben.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-23 17:49:08 +02:00
parent b595c75eef
commit e727262539
2 changed files with 172 additions and 0 deletions

View File

@@ -353,6 +353,8 @@ FT kaschierte das bisher als „Roaming" statt „schwache Abdeckung".
- **Beide in MikroMCP `routers.yaml`** (crs326-core/-branch, ENV `ROUTER_CRS326_*` in `~/.claude.json` — **live erst nach MCP-Neustart**, diese Session lief alles per REST-curl). **Nautobot** modelliert + GraphQL-verifiziert (`nautobot/ingest-crs326-ports.py`): branch Active + volle Ports + primary_ip4 `.99.13`; core Planned + tentatives Layout; **sw1 verifizierte 16-Port-Belegung** (löst „UNVERIFIZIERT"); **sw2 → Decommissioning**.
- 🐞 **Gotchas festgehalten:** (1) **Kabel ether3↔ether5 waren beim Umstecken vertauscht** → ein AZ-Sonos landete als Access-VLAN10 in `10.40.10.190` **und** blutete via SonosNet nach VLAN40 (= Dual-Homing-Muster, `project_dual_homing_slowness_incident`) → Kabeltausch gefixt, beide AZ-Sonos jetzt sauber VLAN40 (`.191`/`.192` bound). (2) RouterOS-Script-`policy`-Feld per REST wählerisch → **weglassen** (admin-Default = volle Policy). (3) Disable-Regex mit `^…$`-Ankern griff nicht → `[find name!="ether1" and …]` nutzen. (4) REST-`PUT`-Antwort mit mehrzeiligem `source` ist kein sauberes JSON → ID separat via `?.proplist=.id` holen. (5) Claude-Code-Auto-Mode-Classifier blockt Device-Config-*Writes* per Bash (Reads ok) → `autoMode.allow`-Regel in `.claude/settings.local.json` nötig (kann Claude sich nicht selbst setzen).
- **🔜 Als Nächstes (eigene Session, Übergabe): Core-Tausch = L3-Umzug** (Routing/DHCP/DNS/CF-Mesh von ap1 → crs326-core) — **Vollausfall-Fenster**, s. `docs/tp15-core-swap-session-handoff-prompt.md`. Danach WLAN-Neuprovisionierung (TP3, CAPsMAN-Abbau). Finaler Mgmt-Renumber dann: branch `.99.13`→`.99.12`, core bleibt `.99.11`.
- ✅ **Core-Swap VORBEREITET (2026-07-23, reine Prep-Session, kein Netz-Eingriff):** ap1s Live-L3-Config vollständig gelesen (MikroMCP) und als **staged Config** materialisiert → `routeros/tp15-core-l3-staged.rsc` (alles Betriebsumlenkende `disabled=yes`, im Cutover in einem Rutsch `enable`; ~50 Reservierungen + WG-Privkey bewusst erst im Fenster maschinell von ap1 geholt statt abgetippt). Runbook/Rollback/Verifikation im Plan. **3 Fenster-Start-Entscheide festgelegt:** (1) **WG-Hub (TP10 FM/DW-VPN) migriert MIT** — war im Handoff-Prompt übersehen, hängt an ap1s Public-Edge und kann dort nicht bleiben; (2) Governance = **frische Direkt-Ausnahme #3** (REST/MikroMCP), danach intended→Nautobot; (3) Rettungspfad = **iPhone-Hotspot**.
- 🐞 **Prep-Gotchas:** (a) **MikroMCP kann core noch nicht schreiben** — `ROUTER_CRS326_CORE_*` im MCP-Prozess nicht geladen (jeder Zugriff „Missing environment variable") → vor dem Fenster MCP neu starten oder REST-curl gegen `http://10.40.41.211/rest`. (b) Mgmt-`.99.11` tot (sw1 #12 trägt kein 99T), nur VLAN1-Temp `.41.211` erreichbar. (c) **WG-Hub-Fallen:** Privkey von ap1 mitnehmen (sonst FM/DW-Reconfig nötig) + Hub-Endpoint der Spokes klären, da core am WAN evtl. neue Liwest-IP zieht (nicht MAC-gelockt). (d) core-vlan99 wird GW `.1`; Bring-up-`.11` dadurch redundant (Fenster-Reconcile). (e) VLAN1 raus: Hybrid-VLAN1-Drops sw1 GE3/7/10 beim Umstecken einem echten VLAN zuordnen oder stilllegen.
- 📦 **2× CRS326-24G-2S+RM werden morgen (2026-07-17) geliefert, Produktivsetzung spätestens Montag 2026-07-20 (User-Entscheid 2026-07-16).** Sequenzierung ggü. Nautobot geklärt: **TP20+TP21 werden bis dahin fast-getrackt** (TP18/Komodo als Blocker entfernt, s. TP20) — Ziel ist, dass Nautobot **vor** der CRS326-Produktivsetzung steht und die Switches **direkt als Nautobot-verwaltete Geräte adoptiert** werden, statt erst von Hand konfiguriert und später importiert. sw1/sw2-VLAN99-Umzug (TP19.1) läuft parallel dazu on-demand, unabhängig davon.
- **🧭 Grundsatzentscheid (2026-07-14, korrigiert 2026-07-15): reines MikroTik-Ecosystem — Routing + Switching + WLAN.** **Omada bekommt KEINE Rolle** (weder Switching noch WLAN — der ursprüngliche „Omada=WLAN"-Satz war ein Fehlschluss beim Dokumentieren, User-Korrektur 2026-07-15: „WLAN war NIE von Omada die Rede"). Begründung Switching: Projektziel #1 **CAKE** nur RouterOS/OpenWrt/OPNsense (Omada-Gateway kann kein CAKE) → Switching = MikroTik CRS. WLAN bleibt auf hAP ax²/CAPsMAN (kein EAP-Kauf), Coverage-Fix bleibt Platzierungsfrage (TP3.3). Verworfene Vollvarianten (Omada-only, MikroTik-only) samt Begründung + Ansible/Nautobot-Recherche → Memory. **Anlass der Korrektur:** Omada-Controller↔sw2-Link beim VLAN20-Umzug (TP14.1) zerbrochen, versehentlicher Werks-Reset bei Rettungsversuch, fehlerhafter Wiederherstellungsversuch → sw2 wird standalone neu eingerichtet, s. **TP2.1**.
- **🛒 Switches: 2× CRS326-24G-2S+RM bestellt (2026-07-14 — CSS326-Fehlbestellung storniert → CRS).** 24×1G + 2×SFP+, lüfterlos, DC-input (USV-tauglich). Lösen ALLNET-Core (sw1) + Omada-ES208G (sw2, s. TP2.1 — Solo/Interim bis CRS-Tausch) + Cudy ab.

View File

@@ -0,0 +1,170 @@
# =====================================================================================
# TP15 — crs326-core L3-Umzug: STAGED CONFIG (ap1 -> core)
# =====================================================================================
# Zweck: core zum L3-Router machen (ersetzt ap1). ALLES was den Betrieb umlenkt, wird
# STAGED (disabled=yes) angelegt -> kein IP-Konflikt mit dem noch aktiven ap1.
# Im Cutover-Fenster werden die disabled-Objekte in EINEM Rutsch aktiviert.
#
# NICHT HEUTE ausführen. Vorbereitungs-Artefakt für ein späteres Wartungsfenster.
# Governance: braucht die zu Fensterbeginn neu zu erteilende Direkt-Ausnahme #3.
# Ausführung: REST (/system/script PUT+run gegen http://10.40.41.211/rest) ODER
# MikroMCP plan_changes->apply_plan (nach MCP-Neustart, ENV CRS326_CORE_* live).
#
# Vorlage = ap1s Live-Config, gelesen 2026-07-23 (MikroMCP). Bridge/VLAN-Filtering/Trunks
# stehen auf core bereits (Bring-up) — hier kommt NUR die L3-Ebene dazu.
#
# ⚠️ ZWEI Bulk-Blöcke bewusst NICHT hier hartkodiert (Transkriptionsfehler-Risiko bei ~50
# MACs) -> zum Fensterbeginn MASCHINELL von ap1 heben, s. Abschnitt [RESERVATIONS].
# ⚠️ WG-Hub PRIVATE KEY ist ein Secret -> NICHT im Repo. Platzhalter unten, am Gerät setzen.
# =====================================================================================
# ============================ [1] INTERFACE-LISTS ====================================
# Voraussetzung für WAN-Seal (input) und NAT (out-interface-list=WAN).
/interface/list add name=WAN comment="TP15"
/interface/list add name=LAN comment="TP15"
/interface/list/member add list=WAN interface=vlan100
/interface/list/member add list=LAN interface=vlan10
/interface/list/member add list=LAN interface=vlan20
/interface/list/member add list=LAN interface=vlan30
/interface/list/member add list=LAN interface=vlan40
/interface/list/member add list=LAN interface=vlan50
/interface/list/member add list=LAN interface=vlan90
/interface/list/member add list=LAN interface=vlan99
# bridge/VLAN1 bewusst NICHT in LAN (VLAN1 raus). vlan99-Mgmt .11 bleibt vorerst separat.
# ============================ [2] GW-IPs je VLAN (STAGED) ============================
# disabled=yes -> erst im Cutover enable (sonst Duplicate-IP mit ap1).
/ip/address add address=10.40.10.1/24 interface=vlan10 comment="MAIN GW" disabled=yes
/ip/address add address=10.40.20.1/24 interface=vlan20 comment="INFRA GW" disabled=yes
/ip/address add address=10.40.30.1/24 interface=vlan30 comment="IOT GW" disabled=yes
/ip/address add address=10.40.40.1/24 interface=vlan40 comment="MEDIA GW" disabled=yes
/ip/address add address=10.40.50.1/24 interface=vlan50 comment="UNTRUSTED GW" disabled=yes
/ip/address add address=10.40.90.1/24 interface=vlan90 comment="GUEST GW" disabled=yes
/ip/address add address=10.40.99.1/24 interface=vlan99 comment="MGMT GW" disabled=yes
# KEIN 10.40.41.x-GW (VLAN1 raus). KEIN Secondary .254 (FB-Legacy, obsolet).
# Reconcile am Gerät: Bring-up-Mgmt 10.40.99.11 vs. GW .1 auf demselben vlan99
# -> .1 ist der Router; .11 als Secondary behalten oder droppen (Fenster-Entscheid).
# ============================ [3] WAN DHCP-Client (STAGED) ===========================
/ip/dhcp-client add interface=vlan100 use-peer-dns=no add-default-route=yes \
comment="TP15 WAN Liwest (Arris)" disabled=yes
# Liwest ist NICHT MAC-gelockt (Public-IP kam mit eigener MAC, s. wan-macclone-test.rsc)
# -> core zieht am WAN evtl. eine ANDERE Public-IP. Konsequenz für WG-Hub s. [7]/[8].
# ============================ [4] DHCP-Server je VLAN (STAGED) =======================
/ip/pool add name=pool-v10 ranges=10.40.10.100-10.40.10.200
/ip/pool add name=pool-v20 ranges=10.40.20.100-10.40.20.200
/ip/pool add name=pool-v30 ranges=10.40.30.100-10.40.30.250
/ip/pool add name=pool-v40 ranges=10.40.40.100-10.40.40.200
/ip/pool add name=pool-v50 ranges=10.40.50.100-10.40.50.200
/ip/pool add name=pool-v90 ranges=10.40.90.100-10.40.90.200
/ip/pool add name=pool-v99 ranges=10.40.99.100-10.40.99.200
# ⚠️ pool-v30 = .100-.250 (Shelly-Reservierungen liegen in-pool, s. TP17). Andere .100-.200.
/ip/dhcp-server/network add address=10.40.10.0/24 gateway=10.40.10.1 dns-server=10.40.10.1 domain=bf.lan
/ip/dhcp-server/network add address=10.40.20.0/24 gateway=10.40.20.1 dns-server=10.40.20.1 domain=bf.lan
/ip/dhcp-server/network add address=10.40.30.0/24 gateway=10.40.30.1 dns-server=10.40.30.1 domain=bf.lan
/ip/dhcp-server/network add address=10.40.40.0/24 gateway=10.40.40.1 dns-server=10.40.40.1 domain=bf.lan
/ip/dhcp-server/network add address=10.40.50.0/24 gateway=10.40.50.1 dns-server=10.40.50.1 domain=bf.lan
/ip/dhcp-server/network add address=10.40.90.0/24 gateway=10.40.90.1 dns-server=10.40.90.1 domain=bf.lan
/ip/dhcp-server/network add address=10.40.99.0/24 gateway=10.40.99.1 dns-server=10.40.99.1 domain=bf.lan
/ip/dhcp-server add name=dhcp-v10 interface=vlan10 address-pool=pool-v10 lease-time=1d add-dns-entries-suffix=lan comment=MAIN disabled=yes
/ip/dhcp-server add name=dhcp-v20 interface=vlan20 address-pool=pool-v20 lease-time=1d add-dns-entries-suffix=lan comment=INFRA disabled=yes
/ip/dhcp-server add name=dhcp-v30 interface=vlan30 address-pool=pool-v30 lease-time=1d add-dns-entries-suffix=lan comment=IOT disabled=yes
/ip/dhcp-server add name=dhcp-v40 interface=vlan40 address-pool=pool-v40 lease-time=1d add-dns-entries-suffix=lan comment=MEDIA disabled=yes
/ip/dhcp-server add name=dhcp-v50 interface=vlan50 address-pool=pool-v50 lease-time=1d add-dns-entries-suffix=lan comment=UNTRUSTED disabled=yes
/ip/dhcp-server add name=dhcp-v90 interface=vlan90 address-pool=pool-v90 lease-time=12h add-dns-entries-suffix=lan comment=GUEST disabled=yes
/ip/dhcp-server add name=dhcp-v99 interface=vlan99 address-pool=pool-v99 lease-time=1d add-dns-entries-suffix=lan comment=MGMT disabled=yes
# ============================ [RESERVATIONS] — MASCHINELL VON ap1 HEBEN ==============
# ~50 statische Leases (26 Shelly, Sonos, NAS .20.10, Nuki, Withings, Sonoff, ccu,
# Airfryer/Mac mit dhcp-option "dns 1.1.1.1", P750W, Ender, DTUBI, tv, ...).
# NICHT abtippen -> am Fensterbeginn auf ap1:
# /ip/dhcp-server/lease/export file=ap1-leases
# dann: nur dynamic=no übernehmen, server-Namen matchen (dhcp-v10..v99), als disabled=yes
# anlegen; im Cutover mit den Servern zusammen enable. Danach GraphQL/HA-Cross-Check.
# (Alternativ MikroMCP manage_dhcp_lease je Eintrag aus dem Live-Read.)
# ============================ [5] DNS ==============================================
/ip/dns set allow-remote-requests=yes servers=1.1.1.1 \
use-doh-server=https://px35ynlol3.cloudflare-gateway.com/dns-query verify-doh-cert=yes \
mdns-repeat-ifaces=vlan10,vlan20,vlan40,vlan30,vlan90
# bridge/VLAN1 NICHT mehr in mdns-repeat (war auf ap1 noch drin, entfällt mit VLAN1).
# Statische A-Records unter bf.lan (11 von ap1; sw1/sw2 RAUS = werden abgebaut):
/ip/dns/static add name=router.lan address=10.40.99.1 comment="core = GW/Router"
/ip/dns/static add name=ap1.bf.lan address=10.40.99.3 comment="ap1 = reiner AP (Mgmt-IP im Fenster festlegen)"
/ip/dns/static add name=ap2.bf.lan address=10.40.99.2 comment="ap2 = reiner AP"
/ip/dns/static add name=core.bf.lan address=10.40.99.1 comment="crs326-core (L3)"
/ip/dns/static add name=branch.bf.lan address=10.40.99.12 comment="crs326-branch (nach Renumber .13->.12)"
/ip/dns/static add name=macmini.bf.lan address=10.40.20.167
/ip/dns/static add name=pve.bf.lan address=10.40.20.100
/ip/dns/static add name=pve-mcp.bf.lan address=10.40.20.173
/ip/dns/static add name=nas.bf.lan address=10.40.20.10
/ip/dns/static add name=docker.bf.lan address=10.40.20.126
/ip/dns/static add name=platform-pg.bf.lan address=10.40.20.20
# ⚠️ ap1/ap2/branch-Mgmt-IPs sind Fenster-Entscheide (Renumber). Oben = Zielannahme.
# ============================ [6] NAT =============================================
/ip/firewall/nat add chain=srcnat dst-address=10.40.0.0/16 action=accept \
comment="TP4: no-NAT inter-VLAN (vor masquerade)"
/ip/firewall/nat add chain=srcnat out-interface-list=WAN action=masquerade \
comment="defconf: masquerade WAN"
# ============================ [7] FIREWALL FILTER =================================
# Reihenfolge = ap1-Live (order-sensitiv!). Gegen ap1-Export im Fenster gegenprüfen.
# --- forward ---
/ip/firewall/filter add chain=forward action=accept connection-state=established,related,untracked comment="defconf: accept est,rel,untracked"
/ip/firewall/filter add chain=forward action=fasttrack-connection connection-state=established,related comment="defconf: fasttrack"
/ip/firewall/filter add chain=forward action=drop connection-state=invalid comment="defconf: drop invalid"
/ip/firewall/filter add chain=forward action=drop connection-nat-state=!dstnat in-interface-list=WAN comment="defconf: drop WAN !dstnat"
/ip/firewall/filter add chain=forward action=accept in-interface=wg-hub comment="TP10: allow from WG spokes (FM/DW)"
/ip/firewall/filter add chain=forward action=accept out-interface=wg-hub comment="TP10: allow to WG spokes (FM/DW)"
/ip/firewall/filter add chain=forward action=accept in-interface=vlan10 out-interface=vlan40 comment="TP5: MAIN->MEDIA (AirPlay/Sonos)"
/ip/firewall/filter add chain=forward action=accept in-interface=vlan40 out-interface=vlan10 comment="TP5: MEDIA->MAIN"
/ip/firewall/filter add chain=forward action=accept in-interface=vlan20 out-interface=vlan40 comment="TP5: INFRA->MEDIA (HA<->Sonos)"
/ip/firewall/filter add chain=forward action=accept in-interface=vlan40 out-interface=vlan20 comment="TP5: MEDIA->INFRA"
/ip/firewall/filter add chain=forward action=accept in-interface=vlan90 out-interface=vlan40 comment="TP5: GUEST->MEDIA (Sonos/Cast)"
/ip/firewall/filter add chain=forward action=accept in-interface=vlan40 out-interface=vlan90 comment="TP5: MEDIA->GUEST"
# --- input (TP10 WAN-Seal) ---
/ip/firewall/filter add chain=input action=accept connection-state=established,related,untracked comment="TP10-seal-est"
/ip/firewall/filter add chain=input action=drop connection-state=invalid comment="TP10-seal-inv"
/ip/firewall/filter add chain=input action=accept protocol=udp dst-port=51821 comment="TP10: WG hub listen"
/ip/firewall/filter add chain=input action=accept protocol=udp dst-port=68 in-interface-list=WAN comment="TP10-seal-dhcp"
/ip/firewall/filter add chain=input action=accept protocol=icmp comment="TP10-seal-icmp"
/ip/firewall/filter add chain=input action=accept in-interface-list=LAN comment="TP10-seal-lan"
/ip/firewall/filter add chain=input action=drop in-interface-list=WAN comment="TP10-seal-wandrop"
/ip/firewall/filter add chain=input action=accept protocol=udp dst-port=5353 in-interface=vlan10 comment="TP5: mDNS in vlan10"
/ip/firewall/filter add chain=input action=accept protocol=udp dst-port=5353 in-interface=vlan40 comment="TP5: mDNS in vlan40"
/ip/firewall/filter add chain=input action=accept protocol=udp dst-port=5353 in-interface=vlan20 comment="TP5: mDNS in vlan20"
/ip/firewall/filter add chain=input action=accept protocol=udp dst-port=5353 in-interface=vlan30 comment="TP5: mDNS in vlan30"
/ip/firewall/filter add chain=input action=accept protocol=udp dst-port=5353 in-interface=vlan90 comment="TP5: mDNS in vlan90"
# Hinweis: ipsec-passthrough-Regeln (defconf) auf ap1 vorhanden aber 0 Pakete -> weggelassen.
# ============================ [8] WG-HUB (TP10 Multi-Site) ========================
# ⚠️ PRIVATE KEY = ap1s wg-hub-Privkey (SECRET, nicht im Repo). Im Fenster von ap1 holen:
# /interface/wireguard/export ODER :put [/interface/wireguard get wg-hub private-key]
# und HIER einsetzen -> core hält denselben Public Key -> FM/DW brauchen KEINE Reconfig.
/interface/wireguard add name=wg-hub mtu=1412 listen-port=51821 private-key="<<< AP1_WG_HUB_PRIVKEY >>>" \
comment="TP10 Multi-Site VPN Hub (FM/DW spokes); kein IP aufs IF (Routing via AllowedIPs)"
/interface/wireguard/peers add interface=wg-hub name=fm allowed-address=10.101.0.0/24 \
public-key="dzRY0lnnUygijChWe5wXZmXPeNcbdALpqBptA3fyiVE=" \
endpoint-address=abxhutfgsid9snmy.myfritz.net endpoint-port=52476
/interface/wireguard/peers add interface=wg-hub name=dw allowed-address=10.95.10.0/24 \
public-key="FqYZLztQ/qME5VDie5QLGH++5299WJiE1dPpQnPbzUw="
/ip/route add dst-address=10.101.0.0/24 gateway=wg-hub comment="TP10: FM spoke -> wg-hub"
/ip/route add dst-address=10.95.10.0/24 gateway=wg-hub comment="TP10: DW spoke -> wg-hub"
# ⚠️ VOR dem Fenster klären: wie adressieren FM/DW den HUB (feste Public-IP vs. DDNS) und
# wer aktualisiert den Record, wenn core am WAN eine neue Liwest-IP zieht? Sonst bleibt
# die Standortkopplung nach dem Cutover tot, bis der Hub-Endpoint nachgezogen ist.
# ============================ [CUTOVER-ENABLE] (im Fenster, EIN Rutsch) ============
# NACH Kabel-Umstecken sw1->core und NACHDEM ap1 als Router still ist:
# /ip/address/enable [find comment~"GW"]
# /ip/dhcp-client/enable [find comment~"TP15 WAN"]
# /ip/dhcp-server/enable [find name~"dhcp-v"]
# (Reservierungen wurden mit angelegt/enabled)
# Dann Verifikation je VLAN (Lease/GW-Ping/Internet), DNS, branch, WG-Handshake, CF/WARP.
# Rollback: hier alles wieder disable + Kabel zurück auf sw1 + ap1 wieder enable.
# =====================================================================================