Merge branch 'tp5-etappe1-log-lauf'
# Conflicts: # docs/teilprojekte.md
This commit is contained in:
@@ -54,7 +54,8 @@ Mgmt (VLAN99, Ist 2026-08-16): core `.99.1` · branch `.99.2` · ap1 `.99.11` ·
|
||||
|
||||
</details>
|
||||
|
||||
**Nächster Schritt (Stand 2026-08-14): TP5 — Deny-by-default am Ende von `forward`.** Alles Davorliegende ist durch: CRS326-Bring-up + L3-Umzug ap1→`crs326-core` (TP15/TP21.1 ✅ 2026-08-08), WLAN-Neuprovisionierung ohne CAPsMAN (TP3 ✅ 2026-08-08), Nautobot-Plattform + Fleet-Adoption + Deploy-Pipeline (TP21/TP22 ✅ 2026-08-13). Danach **TP6 (CAKE) = das Projektziel**. Kleine Follow-ups nebenher: DoH-Cloudflare auf core, DC-USV (**TP24**, seit 2026-08-16 eigener TP). ⚪ **Omada-PVID-Fix ist obsolet** (User-Entscheid 2026-07-22 — Omada spielt seit der TP15-Korrektur keine Rolle mehr im Netz, nie mehr aufgreifen).
|
||||
**Nächster Schritt (Stand 2026-08-17): TP5 Etappe 3 — den Drop scharf schalten, sobald das Log mehrere Tage still bleibt.** Etappe 1 (Log-Lauf) und **Etappe 2 (11 Whitelist-Regeln, ausgerollt 2026-08-17)** sind durch; die Log-Regel ist im Moment des Deploys verstummt. Offene Vorbedingungen für Etappe 3: **mehrtägiges stilles Fenster**, iPhone `.30.201` aus dem IOT-SSID (D2), `seal-lan` verengen. Parallel neu: **TP25** (WLAN-Stabilisierung — Audit durch, 6 Funde) und **TP16.3** (cloudflared-Reduktion via Mesh — Recherche durch).
|
||||
> *Vorherige Fassung (Stand 2026-08-14, überholt): „TP5 — Deny-by-default am Ende von `forward`." Alles Davorliegende ist durch:* CRS326-Bring-up + L3-Umzug ap1→`crs326-core` (TP15/TP21.1 ✅ 2026-08-08), WLAN-Neuprovisionierung ohne CAPsMAN (TP3 ✅ 2026-08-08), Nautobot-Plattform + Fleet-Adoption + Deploy-Pipeline (TP21/TP22 ✅ 2026-08-13). Danach **TP6 (CAKE) = das Projektziel**. Kleine Follow-ups nebenher: DoH-Cloudflare auf core, DC-USV (**TP24**, seit 2026-08-16 eigener TP). ⚪ **Omada-PVID-Fix ist obsolet** (User-Entscheid 2026-07-22 — Omada spielt seit der TP15-Korrektur keine Rolle mehr im Netz, nie mehr aufgreifen).
|
||||
> *Vorherige Fassung (Stand 2026-07-22, erledigt): „TP15 CRS326-Bring-up als neuer L3-Core, danach WLAN-Neuprovisionierung ohne CAPsMAN; TP5 folgt nach TP21/CRS326-Adoption."*
|
||||
> 🎯 **Ziel: sauberes System „from scratch", keine Leichen/Altlasten.** Migrations-Session-Endstand = **VLAN1 + altes cudy-WLAN komplett weg** (VLAN1 nur noch Mgmt, `defconf`-Client-DHCP zurückgezogen, cudy-Uplinks aufs Ziel-Client-VLAN getaggt oder cudy abgebaut). **Unterpunkte/Aufräum-Liste bei Migration:** (a) die Interim-Härtung ap2 `wifi1/wifi2 frame-types=admit-only-vlan-tagged` (TP3.1, 2026-07-06) bleibt gültig — verschwindet automatisch mit VLAN1; (b) ~~`st-main rrm/wnm` = reines Roaming-Provisorium~~ → **kein Provisorium mehr (2026-08-13, TP3.3): Steering ist fester Bestandteil des Golden-Config-Templates + ComplianceFeature `wifi-steering`** — es war die Neuprovisionierung, die es stillschweigend verloren hatte; (c) ~~**cudy1 = verbleibender aktiver VLAN1-Leak**~~ → **ERLEDIGT (User-bestätigt + verifiziert 2026-08-14): cudy1 ist offline.** `core ether11` trägt **kein Link** (kein `R`-Flag), Nautobot-Status *Offline* (TP22 Schritt 5). Damit existiert kein aktiver VLAN1-Leak mehr; der Dual-DHCP-Race aus `project_vlan1_dhcp_incident` ist Historie. Der formale Teardown (Gerät ausbauen, Doku/Inventar) bleibt TP19.
|
||||
> ⚠️ **HW-Constraint hAP ax²:** 1 GB RAM, aber nur **128 MB Flash + KEIN USB** → **Container auf dem Router NICHT praktikabel**.
|
||||
@@ -236,7 +237,56 @@ FT kaschierte das bisher als „Roaming" statt „schwache Abdeckung".
|
||||
- Abh.: TP1 ✅. TP3-Abhängigkeit entfällt (WLAN läuft weiterhin über FB bis TP3).
|
||||
- **Ermöglicht jetzt:** PVID-Fix in Omada-Profilen (MAIN→PVID10, INFRA→PVID20), untagNetworkIds-Bereinigung, DHCP-Reservierungen für NAS/macmini/pve auf neue VLAN-Subnetze migrieren.
|
||||
|
||||
### TP5 — Firewall & Inter-VLAN-Policy ▸ ⏳ TEIL-LIVE auf `crs326-core` (Holes + WAN-Seal re-verifiziert 2026-08-14; Deny-by-default steht aus) — **jetzt das nächste Arbeitspaket, Session vorbereitet** — 📋 `docs/tp5-deny-by-default-runbook.md`
|
||||
### TP5 — Firewall & Inter-VLAN-Policy ▸ 🟢 **ETAPPE 2 AUSGEROLLT (2026-08-17): 11 Whitelist-Regeln live, Log-Regel verstummt** — 📋 `docs/tp5-deny-by-default-runbook.md`
|
||||
|
||||
- ✅ **ETAPPE 2 DURCH (2026-08-17) — `routeros/tp5-etappe2-whitelists.rsc`, ConfigPlan `86fbd528`, Backup `core-pre-tp5-etappe2-20260817.backup`.**
|
||||
- **Basis waren 43.027 Logzeilen** aus dem Fenster 2026-08-16T17:21 → 2026-08-17T14:05 (Kollektor `10.40.20.18`),
|
||||
also **~21 Stunden echter Nutzverkehr** statt der 10-Minuten-Stichprobe von Etappe 1. Die vollständige Matrix:
|
||||
| Paar | Zeilen | Dienste (Ziel:Port, absteigend) |
|
||||
|---|---|---|
|
||||
| `vlan20 → vlan99` | **20.682** | `8728` auf branch (7468) / ap1 (7468) / ap2 (5731) = HA-`mikrotik`-Integration · `:22` je 8 = Nautobot-Netmiko |
|
||||
| `vlan10 → vlan20` | **8.082** | macmini `udp/3722` **6234** (Continuity) · NAS `6690` 1578 · Nautobot `8080` 137 · AirPlay `7000` 69 · pve-mcp `3000` 22 · HA `9583` 16 · pve `:22` 12 · macmini `49152`/`udp 59107` je 8 · NAS `:22` 4 · **Ollama `11434`** 2 |
|
||||
| `vlan20 → vlan10` | **7.123** | Rückrichtung Continuity (eigene Flows je Richtung) |
|
||||
| `vlan20 → vlan30` | **6.238** | HA pollt ~22 Shellys auf `tcp/80` |
|
||||
| `vlan30 → vlan20` | 306 | **`.30.249` → HA `8123`** (203) · macmini `49152` (1) |
|
||||
| `vlan10 → vlan30` | 237 | **nur** `udp/3722` → `.30.201` = das iPhone im IOT-SSID (D2) |
|
||||
| `vlan10 → vlan99` | 214 | Arbeitsplatz `.10.82` → branch/ap1/ap2 `:22`/`:80`/`:443` |
|
||||
| `cf-mesh → *` | **137** | `100.96.0.1` → Nautobot `8080` (62) · NAS `6690` (46) · macmini/NAS/branch/ap1/ap2 `:22` · pve `8006` · pve-mcp `3000` |
|
||||
| `vlan10 → vlan10` | 17 | same-VLAN mDNS `5353` (vom Repeater auf dem Core) |
|
||||
| **`vlan40`/`vlan50`/`vlan90`** | **0** | ➡️ **D6 bestätigt: Internet-only-Pinning ist risikofrei.** `out:bridge` kommt **nicht mehr vor** (VLAN1-Rückbau hält). |
|
||||
- **Entscheidungen (User 2026-08-17):** **D1 = MAIN→INFRA pauschal** (MAIN *ist* das Trusted-VLAN; 13 Einzelports
|
||||
wären eine Wartungsfalle, die bei jedem neuen Dienst still bricht). **D4 = MGMT named sources** — MAIN komplett
|
||||
+ HA `.20.105:8728` + Nautobot `.20.30:22` + `cf-mesh`, Rest drop. **D5** = beobachtetes `8123` + MQTT als Absicht;
|
||||
**Influx `8086` NICHT** (nie beobachtet, der Weg läuft über HA).
|
||||
- 🎯 **ABNAHME am Gerät bestanden:** 11 Regeln (`*1B`–`*25`) existieren, `disabled=false`, **alle vor der Log-Regel**
|
||||
(`place-before`, sonst wäre das Gate unten nicht messbar), Selbstprotokoll `tp5e2: ENDE whitelist-regeln=11`.
|
||||
**Und der Zähler der Log-Regel steht: 54.129 bei 14:17:06 und unverändert bei 14:18:13; die letzte Zeile im
|
||||
Kollektor ist `14:17:16` — genau der Deploy-Zeitpunkt.** Die Regel ist also **verstummt**.
|
||||
- ⚠️ **Aber das ist noch KEIN Freibrief für Etappe 3.** 70 Sekunden Stille sind keine Aussage — das Runbook
|
||||
verlangt bewusst „einige Tage", weil Geräte existieren, die **einmal pro Woche** funken (Backup-Jobs,
|
||||
Drucker-Discovery). **Gate für Etappe 3: mehrtägiges Fenster ohne neue Zeilen.**
|
||||
- 📌 **Zwei Dinge müssen VOR dem Drop passieren:** (a) **D2** — iPhone `.30.201` ins MAIN-SSID umhängen
|
||||
(Hands-on Christoph); solange es im IOT-SSID hängt, killt der Drop die 237 `udp/3722`-Flows. Eine Whitelist
|
||||
darauf wäre instabil, weil iOS **pro SSID** eine eigene Private Address vergibt. (b) `seal-lan` verengen (D4
|
||||
`input`-Teil), was zugleich die 5 toten mDNS-`input`-Regeln scharf schaltet.
|
||||
- ✅ **ABNAHME DES VLAN1-RÜCKBAUS BESTANDEN (2026-08-16): `out:bridge` = 0.** 10-Minuten-Messfenster nach dem Wiederanschalten, Logdatei vorher geleert. Vorher waren `vlan20 → bridge` **76 %** des gesamten Inter-VLAN-Verkehrs. Die Rate fiel von ~166 auf ~34 Zeilen/min — der Rückbau hat das Log auf echten Nutzverkehr eingedampft. Wiederaufnahme über `routeros/tp5-etappe1-resume.rsc` (GC, Backup `core-pre-tp5-resume-20260815.backup`).
|
||||
- 📊 **Beobachtete Matrix, 339 Zeilen / 10 min** — das Arbeitsmaterial für Etappe 2:
|
||||
|
||||
| Paar | Zeilen | was genau |
|
||||
|---|---|---|
|
||||
| `vlan20 → vlan99` | 126 | **HA `10.40.20.105` → `10.40.99.2:8728` + `10.40.99.11:8728`** (je 67) = der Management-Pfad |
|
||||
| `vlan20 → vlan30` | 85 | HA → IoT: `.30.211:80` (44), `.30.8:10081` (22), `.30.244:8080` Nuki (22), `.30.5:631` Drucker (4) |
|
||||
| `vlan10 → vlan20` | 65 | Arbeitsplatz → INFRA |
|
||||
| `vlan20 → vlan10` | 61 | INFRA → MAIN |
|
||||
| `vlan10 → vlan10` | 2 | **mDNS `10.40.10.183:5353 → 10.40.10.82:5353`** — s.u. |
|
||||
|
||||
- 🔑 **D4 ist damit belegt, nicht mehr geschätzt:** der Management-Pfad ist **HA** (`10.40.20.105`), das über seine vier `mikrotik`-Integrationen `8728` auf branch/ap1/ap2 pollt (core `.99.1` erscheint nicht, weil das `input` ist, nicht `forward`). Dazu MikroMCP vom Arbeitsplatz. **Ohne Whitelist sperrt der spätere Drop die Verwaltung des eigenen Netzes aus.**
|
||||
- ⚠️ **Neuer Merkposten für Etappe 3 — same-VLAN-Verkehr erreicht die `forward`-Kette:** `vlan10 → vlan10`, unicast **mDNS** zwischen zwei MAIN-Clients, erzeugt vom mDNS-Repeater auf dem Core. Zwei Pakete in 10 Minuten, harmlos — **aber ein blanker Drop am Kettenende würde sie treffen** und damit Discovery *innerhalb* von MAIN beschädigen. Zusammen mit `accept out-interface-list=WAN` die zweite Regel, die bekannt ist und nicht aus dem Log wiederentdeckt werden muss.
|
||||
- ✅ **D2 vollzogen:** iPhone ist im MAIN-SSID, `10.40.30.201` steht im ARP auf `failed`.
|
||||
- ✅ **Etappe 1 ausgerollt 2026-08-14** (über Nautobot GC, manual Config Plans; Backups `core-pre-/post-tp5-etappe1-20260814.backup`). Auf dem Gerät: `forward`-Regel `action=log log-prefix="TP5-WOULD-DROP"` am Kettenende, Syslog-Action `tp5syslog` → **Kollektor `10.40.20.18:514`** (syslog-ng-Container `tp5-syslog` auf dem Docker-LXC, Logs `/opt/tp5-syslog/log/`, 10-Minuten-Cron kappt bei 500 MB — der LXC hat nur ~2,5 GB frei). `firewall` ist aus dem Memory-Ring genommen (`topics=info,!firewall`), sonst wäre der On-Box-Log tagelang unbrauchbar. **Blockiert nichts.** Artefakte: `routeros/tp5-etappe1-log-lauf.rsc`, Push-Werkzeug `nautobot/gc-manual-plan.py`. Compliance danach **16/17** (der eine Rotpunkt `ip-address` = bekannte VLAN1-Bring-up-IP `10.40.41.211` aus dem TP22-Backlog, **keine neue Drift**).
|
||||
- 🔴 **Fund aus dem Log-Lauf, der Etappe 3 bestimmt: die Regel fing anfangs auch allen Internet-Verkehr** (`out:vlan100`, ~¼ der Zeilen in einer ruhigen Minute, unter Last mehr). Die Log-Regel steht deshalb jetzt auf `out-interface-list="!WAN"`. **Konsequenz für den späteren Drop: er darf NICHT bare ans Kettenende** — davor gehört `accept out-interface-list=WAN`, sonst ist das ganze Haus offline. Diese Whitelist-Zeile ist damit bekannt und muss nicht aus dem Log wiederentdeckt werden.
|
||||
- 🔍 **Erste Befunde nach 60 s** (Rate nach Einengung ~166 Zeilen/min): **76 % des Inter-VLAN-Verkehrs ist `vlan20 → bridge`, also INFRA nach VLAN1** — ein Monitoring-Host `10.40.20.151` scrapet ~10 tote/alte `10.40.41.x`-Ziele, HA `.20.105` zieht auf `10.40.41.100:8006` (pve unter seiner **alten** VLAN1-Adresse, real `.20.100`), `.20.107` auf `10.40.41.10:8080`. **Das ist TP19-Material, das TP5 gerade sichtbar macht.** Weiter: `vlan20 → vlan99:8728` (MikroTik-API auf branch/ap1/ap2 = **der Management-Pfad selbst**, muss in die Whitelist, betrifft D4), `vlan20 → vlan30` (HA → Drucker `.30.5:631`, Shelly, Nuki `.30.244:8080`), `vlan10 ↔ vlan20` (Synology Drive `6690`, Apple-Continuity `udp/3722`).
|
||||
- ✅ **D2 entschieden (User 2026-08-14): iPhone wird ins MAIN-SSID umgehängt.** Faktenlage war: `10.40.30.201`, dynamische Lease, Hostname `iPhone`, MAC `12:99:A6:AC:B0:CB` = iOS Private Wi-Fi Address, aktiv auf `dirtyvader-iot` mit 748 MB rx. Die statische Reservierung `10.40.10.196` „iPhone" (andere private MAC — iOS vergibt **pro SSID** eine eigene) belegt, dass es dasselbe Telefon ist. **Umhängen ist die Hands-on-Aufgabe von Christoph** (SSID am Gerät wechseln + `dirtyvader-iot` vergessen lassen); technisches Argument: eine Whitelist auf eine rotierende Private MAC wäre ohnehin instabil.
|
||||
- 📋 **Session-Runbook liegt (2026-08-14): `docs/tp5-deny-by-default-runbook.md`** — Ist-Stand live erhoben, **beobachtete Inter-VLAN-Flow-Matrix** (conntrack + Counter), 6 offene Entscheidungen (D1–D6), 4 Etappen mit Absicherung, Verifikation + Rollback. **Kernansatz: Etappe 1 ist ein reiner Log-Lauf ohne Blockierung** (`action=log` ans Ende von `forward`) — die Whitelist wird aus dem Log abgeleitet, nicht am Schreibtisch geraten. Drei Funde, die vorab eine Entscheidung brauchen: ein **iPhone sitzt in VLAN30**, ein **ICMP-Dauersweep von `.10.82` auf alle Shellys**, und **vlan99 ist Mitglied der `LAN`-Liste** (→ `seal-lan` erlaubt Mgmt-Input aus jedem VLAN). **VLAN50/90 tragen null Inter-VLAN-Verkehr** → Internet-only-Pinning ist dort risikofrei.
|
||||
- **Deny-by-default + least-privilege** (Ziel). MAIN→INFRA nur Whitelist-Dienste; MAIN↔MEDIA allow (+mDNS); UNTRUSTED/GUEST nur Internet; MGMT isoliert; Router-input gehärtet.
|
||||
- ⚠️ **Gerätewechsel beachten (2026-08-14 nachgetragen):** der ✅-Block unten war ursprünglich **auf ap1** verifiziert (2026-07-02) — ap1 ist seit 2026-08-08 Werksreset und reiner AP. Die Regeln sind beim Core-Cutover (TP21.1) mitgewandert, waren am neuen Gerät aber **nie gegengeprüft**. Am **2026-08-14 auf `crs326-core` live nachverifiziert** (`list_firewall_rules`, chains `forward` 13 Regeln / `input` 12 Regeln): **alle unten gelisteten Regeln existieren, sind enabled, tragen ihre `TP5:`/`TP10-seal-`-Kommentare und zählen Traffic.** Merkregel: nach jedem Rollenwechsel eines Geräts gilt eine Verifikation vom Vorgänger nicht weiter.
|
||||
@@ -577,7 +627,26 @@ FT kaschierte das bisher als „Roaming" statt „schwache Abdeckung".
|
||||
- **`crs326-core` hat keine VLAN1-IP mehr:** `/ip/address` listet nur noch die 7 SVIs + die WAN-DHCP-Adresse — die **Bring-up-Altlast `10.40.41.211` ist weg**. Damit fällt einer der 5 Compliance-Drifts aus TP22 raus, *sobald* wieder **Backup → Intended → Compliance** gelaufen ist (die Compliance vergleicht gegen das letzte Backup, nicht gegen das Gerät — s. TP22-Falle).
|
||||
- ✅ **`crs326-branch`-Interim ERLEDIGT (2026-08-16):** `10.40.10.2` + SVI `vlan10` über einen GC-ConfigPlan entfernt (s. TP22). Mgmt läuft über `.99.2`; `/interface bridge vlan` blieb byte-identisch, es gibt also weder einen Traffic- noch einen Drift-Effekt.
|
||||
- **`.41.133` identifiziert** (war TP19 B1.2 „unidentifiziertes VLAN1-Gerät"): es ist das **coolify-Origin** aus dem gleichnamigen, seit Monaten toten CF-Tunnel. Ebenso `.41.147/.148/.139` aus dem toten `openclaw`-Tunnel. Keine aktiven Geräte — **Karteileichen in der Cloudflare-Config**, nicht im Netz. Aufräumen = die 4 toten Tunnel löschen (user-gated, s. TP16-Nebenbefund).
|
||||
- ⚠️ **Eskaliert 2026-07-15 (historisch — durch den WLAN-Rebuild 2026-08-08 gegenstandslos):** der unter TP3.1 dokumentierte VLAN1-Leak tritt jetzt auch auf ap1/`dirtyvader-main` auf — die ap-seitige Interim-Härtung (TP3.1) mildert das Symptom, **die endgültige Lösung ist hier, TP19**: VLAN1 physisch weg = kein Leck mehr möglich. Das erhöht die Dringlichkeit dieses TPs, verschiebt aber keinen Scope hierher.
|
||||
- ✅ **VLAN1-Adressen abgeräumt (2026-08-15) — der Weg dorthin** — `docs/vlan1-rueckbau-howto-manuelle-schritte.md`:
|
||||
- **pve `10.40.41.100` weg** (`/etc/network/interfaces`: `vmbr0` von `inet static` auf `inet manual`, Adresszeile raus; angewendet per `ip addr del` **ohne** `ifreload -a`, damit die Bridge nicht durchgetreten wird). Nachher nur noch `vmbr0.20`, keine `41.0/24`-Route, alle 9 Gäste weiter `running`, Storage aktiv. Backup `/root/interfaces.bak-tp19-20260815-183045`.
|
||||
- **Core `10.40.41.211` weg** über Nautobot GC (`routeros/tp19-core-vlan1-address-remove.rsc`). Mgmt `.99.1` + `10.40.10.1` intakt. Compliance damals 17/17 grün — der TP22-Backlog-Punkt „`crs326-core 10.40.41.211`" entfällt. *(Zahl inzwischen überholt: nach TP16.1 sind es 72/72 Checks.)*
|
||||
- **HA zeigt auf `10.40.20.100`** (User), **ioBroker** korrigiert (User).
|
||||
- **Prometheus bereinigt.** Der pauschale `41`→`20`-Ersatz war eine Falle: nur `grafana` (`.20.109`) und `n8n` (`.20.167:5678`) liefern echte Metriken. `gitea` hat `/metrics` gar nicht aktiviert, `vaultwarden` gibt 404, `portainer /api/status` liefert JSON statt Prometheus-Format, `node`/`alertmanager`/`qdrant` sind exited, `pihole` ist abgewählt → **8 Jobs + `alerting:`-Block auskommentiert**, 3 aktive Ziele, alle `up`.
|
||||
- 🔴 **NAS-Falle:** `prometheus.yml` gehört `65534:65534`, das Verzeichnis `adm.christoph` → `cat > datei` scheitert still („Permission denied"), während ein `cp` daneben klappt. **Schreiben per `sudo tee` + `md5sum`-Gegenprobe**, nie der Shell-Erfolgsmeldung trauen.
|
||||
- ⏳ **OFFEN: HA-Portainer-Integration bleibt auf `setup_retry` — `docker system df` auf nas-bf ist zu langsam.** Aus dem HA-Debug-Log: `PortainerTimeoutError … GET /api/endpoints/14/docker/system/df` → `ConfigEntryNotReady`. Die Integration ruft `system df` für **jede** Umgebung bei **jedem** Update auf.
|
||||
- **Container-Manager-Neustart am 2026-08-15 durchgeführt** (`/usr/syno/bin/synopkg stop|start ContainerManager` — Binary **nicht** im sudo-PATH; DSM meldet den Status danach weiterhin falsch als `stop`). **Alle 14 Container aus der Baseline zurück**, zusätzlich kam `hms-mqtt` hoch (Restart-Policy `always`, lief vorher nicht).
|
||||
- ✅ **`hms-mqtt` stillgelegt (2026-08-16, User: „wird bald platt gemacht").** Es war bereits beendet; entscheidend war die **Restart-Policy `always` → `no`** (`docker update --restart=no`), sonst wäre es beim nächsten Daemon-Neustart wiedergekommen. Ein bloßes `docker stop` hätte hier nicht gehalten.
|
||||
- ✅ Der **Hänger** ist damit weg: `system df` beendet sich wieder (vorher rc=124 nach Ausgabe der Tabelle). ❌ **Aber es bleibt viel zu langsam und schwankt: 33 s → 92 s → 3× >120 s.**
|
||||
- 🔑 **Wo die Zeit hingeht (gemessen):** `images -q` 84 ms · `ps -aq` 95 ms · `volume ls -q` 65 ms · **`system df` 33–92+ s**. Also **vollständig in der Größenberechnung** (du-artiger Durchlauf der overlay2-/Volume-Verzeichnisse auf NAS-Platten) — ein struktureller Plattformnachteil, kein Defekt. Die Mengen sind harmlos (25 Images/13 GB, 10 Volumes/79 MB).
|
||||
- **Aussichtsreichster Weg: eigener Portainer-Benutzer für HA ohne Zugriff auf ep14** → die Integration sieht die langsame Umgebung gar nicht. User-gated (Benutzer + Token anlegen). Alternativen: nichts tun (stört nichts) · Images aufräumen (6,98 GB reclaimable, Erfolg **offen**) · ep14 aus Portainer nehmen (schlechter Tausch).
|
||||
- ⚠️ **Zwei widerlegte Zwischenthesen, nicht wieder aufgreifen:** die tote Umgebung `odroid-m1` war es **nicht** (entfernt, Symptom blieb, alle übrigen Endpoints ≤0,16 s); und es ist **kein** Größenproblem der Images.
|
||||
- ✅ **Restliste aus dem TP5-Log-Lauf — ABGEARBEITET (Abnahme 2026-08-16: `out:bridge` = 0 über 10 min, Rate von ~166 auf ~34 Zeilen/min gefallen; im 43k-Zeilen-Log vom 08-17 kommt `out:bridge` nicht mehr vor).** Wert dieses Eintrags = die Diagnosemethode, nicht der Stand. Der Log-Lauf hatte gezeigt, dass **76 % allen Inter-VLAN-Verkehrs** aus VLAN20 nach VLAN1 (`out:bridge`) ging, obwohl dort **nichts mehr antwortete** (alle Ziele im ARP `failed`/`incomplete`). Verursacher waren Konfigurationen, die nie nachgezogen wurden:
|
||||
- **`prometheus` (`10.40.20.151`, NAS)** scrapet 10 tote Ziele: `10.40.41.109:3000` · `.126:9443` · `.127:80` · `.147:5678` · `.149:3000` · `.152:3001` · `.153:9093` · `.154:9100` · `.159:6333` · `.23:80`.
|
||||
- **`10.40.20.105`** zieht auf `10.40.41.100:8006` = **pve unter seiner alten VLAN1-Adresse** (real `10.40.20.100`).
|
||||
- **`10.40.20.107`** auf `10.40.41.10:8080` (NAS alt).
|
||||
- 📌 **Umzugsregel: das letzte Oktett bleibt gleich, nur `41`→`20`** — belegt für grafana (`.109`), vaultwarden (`.127`), Portainer (`.126`). Für `.23/.147/.149/.152/.153/.154/.159` existiert **kein** laufendes VLAN20-Gegenstück (anderswo oder tot; `alertmanager` ist seit TP14.1 als kaputt notiert) → diese Ziele gehören geprüft und dann aus Prometheus entfernt, nicht umgeschrieben.
|
||||
- ⚠️ **Kein Firewall-/Portproblem** (2026-08-14 geprüft, nachdem beim Umstellen ein Timeout auftrat): `pveproxy` lauscht auf `*:8006`, `pve-firewall` ist *disabled*, keine iptables-Regel, kein `/etc/default/pveproxy`. `https://10.40.20.100:8006` antwortet aus VLAN10 **und** VLAN20 mit HTTP 200 in ~0,06 s. Wer hier einen Timeout sieht, sucht an der falschen Stelle — **und `timeout` gibt es auf macOS nicht**, ein `timeout bash -c '… /dev/tcp/…'`-Test meldet deshalb falsch-negativ.
|
||||
- ⚠️ **Eskaliert 2026-07-15 (historisch — durch den WLAN-Rebuild 2026-08-08 gegenstandslos):** der unter TP3.1 dokumentierte VLAN1-Leak trat damals auch auf ap1/`dirtyvader-main` auf — die ap-seitige Interim-Härtung (TP3.1) milderte das Symptom, **die endgültige Lösung ist hier, TP19**: VLAN1 physisch weg = kein Leck mehr möglich.
|
||||
- 🟢 **cudy-Stand (User 2026-07-16): cudy1 (`.41.246`) auf `10.40.10.246` umgehängt** — bewusst **kein Abbau-Ziel mehr**, dient als Standalone-WLAN-Sender während der Umstellungsphase (nicht Teil des Teardowns, extern vom User selbst umkonfiguriert). **cudy2 (`.41.247`) wird nicht mehr reaktiviert** — faktisch tot, ARP-Sweep bestätigt keine Präsenz mehr auf VLAN1. B2.2 („cudy1/cudy2 stromlos/Reset/ausbauen") ist damit **erledigt/gegenstandslos** (cudy2 aus, cudy1 schon migriert statt abgebaut).
|
||||
- 🟢 **Live-Sweep 2026-07-16 (ap1, vor geplantem Teardown):** VLAN1 ist bereits viel weiter zurückgebaut als dokumentiert:
|
||||
- `defconf`/pool-v1-DHCP-Server ist bereits **`disabled=yes`** (Export bestätigt) — B2.4 („defconf zurückziehen") ist **de facto schon erledigt**, Ursprung/Zeitpunkt dieser Änderung nicht aus dieser Session bekannt (nicht in dieser Doku protokolliert).
|
||||
@@ -811,6 +880,196 @@ FT kaschierte das bisher als „Roaming" statt „schwache Abdeckung".
|
||||
- **Abh.:** keine harten. **TP15 ✅** (die zu versorgende Hardware steht und hat DC-Eingänge). Verwandt: **TP18** (Garage-Nodes brauchen je Site eine Stromversorgung), **TP11** (USV-Zustand ins Monitoring). **Kein Blocker für TP5/TP6.**
|
||||
- **Historie:** war bis 2026-08-16 Unterpunkt von TP15 („🔋 DC-USV: MeanWell LRS-150-48 + DDR-120-48 + LiFePO4 20Ah (~€190), 48V-Bus; CRS326 DC-input passt"). Vollständige Recherche inkl. Schaltbild, Effizienzvergleich und Gerätetabelle: `docs/hw-refresh-requirements.md §9` (+ §10 D/E/F für die offenen Fragen).
|
||||
|
||||
### TP25 — WLAN-Stabilisierung: Best-Practice-Audit statt Bauchgefühl ▸ ⏳ **AUDIT DURCH (2026-08-17), Umsetzung offen** — Sammel-TP für Christophs Beobachtungen 1–6
|
||||
> **Warum eigener TP:** Christoph hat am 2026-08-16/17 sechs konkrete Beobachtungen gemeldet und ausdrücklich
|
||||
> **einen** TP dafür verlangt. Sie hängen alle an derselben Ursache-Klasse (Funkparameter, die nicht nach Manual
|
||||
> gesetzt sind), gehören also zusammen. **TP25 übernimmt den offenen Rest von TP3.3** (Re-Walk, Dead-Spot-Kartierung)
|
||||
> — dieselbe physische Arbeit, doppelt geführt wäre Unsinn. TP3.2/TP3.3 bleiben als Historie stehen.
|
||||
> **User-Randbedingung (2026-08-17, wörtlich): „ich weigere mich einen anderen access point zu kaufen solange ich
|
||||
> nicht das gefühl habe, wir haben alles aus dem ap rausgeholt."** Das ist die Abnahmebedingung dieses TPs —
|
||||
> keine Hardware-Empfehlung, bevor die Parameter stimmen.
|
||||
|
||||
- ⚠️ **Ausgangslage: Drift ist bestätigt, aber NICHT die Ursache.** Christoph hat am 08-16/17 selbst an den APs
|
||||
gespielt („drift ist garantiert. es hat vorher aber auch nicht funktioniert"). Der Audit unten ist gegen den
|
||||
**Ist-Stand** gefahren (`/interface/wifi/export` + `/interface/wifi/monitor` + Log, beide APs, 2026-08-17 14:01).
|
||||
Zwei der Funde sind älter als die Experimente und stammen aus der TP3-Neuprovisionierung.
|
||||
|
||||
#### 🔴 Fund A — 2,4 GHz läuft auf 40 MHz, obwohl das Profil 20 MHz sagt (Beobachtung 4)
|
||||
- **Christophs Frage war berechtigt, aber der Adressat ist ein Override, keine Entscheidung.** Das Channel-Profil
|
||||
ist korrekt: `add band=2ghz-ax frequency=2412 name=ch-2g width=20mhz`. **Überschrieben wird es inline am Radio:**
|
||||
`set [find default-name=wifi2] channel.band=2ghz-ax .skip-dfs-channels=10min-cac .width=20/40mhz`
|
||||
→ **das Inline-Override gewinnt gegen das verlinkte Profil.** `monitor` beweist es: ap1 `2412/ax/Ce`,
|
||||
ap2 `2462/ax/eC` — `Ce`/`eC` = 40 MHz. **Niemand hat 20/40 „gewählt"**; es ist genau die Override-Klasse, die
|
||||
CLAUDE.md für den TP3-Bring-up schon dokumentiert („Werks-Inline-Overrides auf wifi1/wifi2 überschreiben das
|
||||
verlinkte Profil") — damals nur für `configuration.ssid`/`security.*` bereinigt, für `channel.*` **nie**.
|
||||
- **Warum 40 MHz auf 2,4 GHz falsch ist (Manual-Ebene, nicht Geschmack):** es gibt nur 3 überlappungsfreie
|
||||
20-MHz-Kanäle. ap1 belegt mit `2412/Ce` ≈ 2402–2442, ap2 mit `2462/eC` ≈ 2442–2482 → **die beiden APs decken
|
||||
zusammen praktisch das ganze Band ab.** Jeder Nachbar-AP überlappt zwangsläufig einen von beiden. Dazu halbiert
|
||||
40 MHz die spektrale Leistungsdichte → **~3 dB weniger Reichweite bei gleicher Sendeleistung.** Und der Nutzen
|
||||
ist null: IoT-Clients sind fast alle 20-MHz-only. **Das ist die „miserable Reichweite" aus Beobachtung 4.**
|
||||
- **Fix:** die Inline-`channel.*`-Overrides auf `wifi1`/`wifi2` **leeren** (`!channel`), damit die Profile greifen.
|
||||
Nebenbefund: `skip-dfs-channels=10min-cac` auf `wifi2` ist bedeutungslos — im 2,4-GHz-Band gibt es keine
|
||||
DFS-Kanäle. Copy-Paste-Spur, harmlos, gehört trotzdem raus.
|
||||
|
||||
#### 🔴 Fund B — ap2 sendet auf 5 GHz mit 9 dBm statt 18 dBm (Beobachtungen 1+2)
|
||||
- **Gemessen:** ap1 `wifi1` `tx-power: 18`, ap2 `wifi1` **`tx-power: 9`** — bei identischer Hardware und
|
||||
identischem Profil. **9 dB Unterschied = Faktor ~8 in der Leistung**, ap2s 5-GHz-Zelle hat grob ein Drittel
|
||||
des Radius von ap1.
|
||||
- **Ursache ist regulatorisch, nicht defekt:** ap2 ist auf **5745 MHz (ch149)** gepinnt. Die Regulatory-Tabelle
|
||||
des Radios für `country=Austria` listet `5745/ax/Ceee` **ohne** `/I`-Flag (indoor) und **ohne** `/D` (DFS) —
|
||||
ETSI-Band C, erlaubt, aber **hart leistungsbegrenzt**. ap1 auf **5180 MHz** bekommt `5180/ax/Ceee/I`, also die
|
||||
Indoor-Freigabe mit voller Leistung. ⚠️ **Die TP3-Notiz „Kanäle non-DFS ap1 ch36/ch1, ap2 ch149/ch11" ist eine
|
||||
FCC-Denkweise.** Non-DFS ist ch149 unter ETSI tatsächlich — aber eben zum Preis der Sendeleistung. Das war der
|
||||
unbemerkte Tauschhandel.
|
||||
- 🎯 **Der Fix löst Fund B und C in einem Zug — und er ist nicht offensichtlich:** unter ETSI Austria existiert
|
||||
im Indoor-Band (5180–5240) **nur ein einziger 80-MHz-Block** (`5180/Ceee` = ch36–48). Zwei APs können dort
|
||||
also nicht beide 80 MHz fahren, ohne sich zu überlappen — **genau deshalb ist ap2 überhaupt auf 5745 gelandet.**
|
||||
Mit **40 MHz** gehen beide sauber ins Indoor-Band:
|
||||
| AP | neu | Kanäle | Leistung | Belegung |
|
||||
|---|---|---|---|---|
|
||||
| ap1 | `5180/Ce` | 36+40 | **18 dBm** | 5170–5210 |
|
||||
| ap2 | `5220/Ce` | 44+48 | **18 dBm** | 5210–5250 |
|
||||
Beide `/I`-freigegeben (aus der Radio-Tabelle bestätigt), überlappungsfrei, **+9 dB für ap2**.
|
||||
|
||||
#### 🔴 Fund C — 80 MHz auf 5 GHz kostet Reichweite, die hier fehlt (Beobachtung 1)
|
||||
- `ch-5g width=20/40/80mhz`, laufend `5180/ax/Ceee` bzw. `5745/ax/Ceee` = **80 MHz**. Dieselbe Sendeleistung auf
|
||||
die vierfache Bandbreite verteilt kostet **~6 dB** effektiven SNR am Zellenrand gegenüber 20 MHz, ~3 dB
|
||||
gegenüber 40 MHz. In einer 2-AP-Wohnung mit Terrasse ist Spitzendurchsatz das falsche Optimierungsziel —
|
||||
**Randabdeckung und Stabilität sind das richtige.**
|
||||
- **Beleg, dass genau das das Terrassen-Symptom ist:** ap1-Log, Telefon steht still im Halter:
|
||||
`-81` → roamt auf 2,4 GHz `-82` → zurück `-83` → **`disconnected, connection lost, signal strength -88`**.
|
||||
**−88 dBm ist unter der Nutzbarkeitsschwelle.** Das ist **kein** Roaming-Problem (Christoph sagt selbst
|
||||
„ich red da nicht mal von roaming"), sondern **Link-Budget** — und dagegen hilft Breite runter, nicht drehen.
|
||||
|
||||
#### 🔴 Fund D — `w2-iot` trägt einen unzulässigen Channel-Override auf einem Slave-VAP (Beobachtung 3)
|
||||
- **ap1:** `add channel.band=2ghz-n .width=20mhz configuration=cfg-iot … master-interface=wifi2 name=w2-iot`
|
||||
- **ap2:** `add channel.width=20mhz configuration=cfg-iot … master-interface=wifi2 name=w2-iot`
|
||||
- **Ein Slave-VAP teilt das Radio des Masters und kann keinen eigenen Kanal haben.** Auf ap1 erzwingt das
|
||||
Override zusätzlich `2ghz-n`, **während der Master `wifi2` auf `2ghz-ax` läuft** — ein Band-Mismatch zwischen
|
||||
Master und Slave ist keine unterstützte Konfiguration. **Das ist der Mechanismus hinter „alle SSIDs sind da,
|
||||
`-iot` beharrlich nicht, und plötzlich ist es wieder da":** der VAP fällt aus der Beacon-Rotation und kommt
|
||||
bei einem Re-Apply zurück.
|
||||
- 📌 **Und es ist der Beweis für Beobachtung 6:** die beiden APs sind hier **nicht identisch** (ap1 mit Band+Width,
|
||||
ap2 nur Width). Eine generierte Config kann das nicht produzieren — das ist Handarbeit, und zwar auf genau dem
|
||||
Objekt, das keine Handarbeit verträgt.
|
||||
|
||||
#### 🟠 Fund E — keine `access-list`, also kein Signal-Boden gegen klebende Clients (Beobachtung 2)
|
||||
- **`/interface/wifi/access-list` ist auf beiden APs leer.** Damit gibt es **keinen `signal-range`-Boden** — ein
|
||||
Client darf hängen bleiben, bis die Verbindung zusammenbricht, statt frühzeitig abgestoßen zu werden. Das ist
|
||||
der Standard-RouterOS-Griff gegen genau dieses Symptom.
|
||||
- **Beleg für das Kleben:** ap2-Log, Client `56:71:6C:22:E6:A9` flappt in 22 Minuten **sechsmal** zwischen
|
||||
`wifi1`↔`wifi2` bei −62…−83 dBm. Und: `F2:62:4C:E1:AF:09@wifi2 disconnected, not responding, signal strength -47`
|
||||
— **Abbruch bei ausgezeichneten −47 dBm.** Beides zusammen = Band-Oszillation ohne Steering-Politik, nicht
|
||||
schlechte Abdeckung.
|
||||
- ⚠️ **Nebenbefund:** die TP3.2-Access-List, die den P750W an ap1 pinnte („überlebt ap2-Re-Provision"), ist
|
||||
**beim Rebuild 2026-08-08 verlorengegangen** — im Export beider APs steht keine einzige Access-List-Zeile.
|
||||
Laut CLAUDE.md ist der Pin nicht mehr nötig (L3-GW liegt auf dem Core), der **Verlust war aber unbemerkt.**
|
||||
- `ft=yes ft-over-ds=no` ist dagegen **korrekt** für Standalone-APs (over-DS bräuchte ein Inter-AP-Protokoll) —
|
||||
kein Fund, nur zur Abgrenzung festgehalten.
|
||||
|
||||
#### 🟡 Fund F — IoT-Clients trennen exakt alle ~5:05 bei gutem Signal (offen, präzise vermessen)
|
||||
```
|
||||
12:55:29 connected -59 → 13:00:36 disconnected -59 (5:07)
|
||||
13:17:27 connected -63 → 13:22:32 disconnected -63 (5:05)
|
||||
13:35:32 connected -60 → 13:40:37 disconnected -59 (5:05)
|
||||
13:57:31 connected -59 → 14:02:35 disconnected -58 (5:04)
|
||||
```
|
||||
- **−59 dBm ist ein gutes Signal. Eine auf 3 Sekunden reproduzierbare 5-Minuten-Periode ist ein Timer, kein Funk.**
|
||||
- 🚫 **Ausdrücklich NICHT die alte Power-Save-Merkregel wiederbeleben** — die ist am 2026-08-13 als Fehldiagnose
|
||||
zurückgezogen worden (`ref_wifi_powersave_multicast`, Drucker war schlicht aus). Dieser Befund ist ein *anderer*:
|
||||
vier saubere Messpaare mit konstanter Periode.
|
||||
- **Kandidaten + der Test, der sie trennt:** (a) periodischer VAP-Re-Apply durch Fund D → prüfen, ob ap2
|
||||
(ohne Band-Override) dieselbe Periode zeigt; (b) DHCP-Lease/Renew-Interaktion → `lease-time` der beiden MACs
|
||||
(`38:A5:C9:C0:73:1E`, `38:A5:C9:BC:33:31`) gegen die Periode legen; (c) das Gerät selbst mit 5-min-Duty-Cycle
|
||||
→ dann bleibt es nach Fund-D-Fix unverändert. **Erst nach dem Fund-D-Fix erneut messen** — sonst misst man zwei
|
||||
Effekte übereinander.
|
||||
|
||||
#### 🧭 Beobachtung 5 — „alle Welt sagt CAPsMAN, nur wir sagen Nautobot GC. Hilfe oder Last?"
|
||||
- **Klare Antwort: es sind keine Alternativen, sie lösen verschiedene Probleme.** CAPsMAN = *Runtime*-Control-Plane
|
||||
fürs WLAN (ein Ort für Radio-Settings, sofortiger Push, dynamische VAPs). Nautobot GC = *Config-as-Code*-SoT
|
||||
+ Drift-Erkennung über die **ganze** Flotte (Core, Branch, beide APs). Man kann beides haben; das Reibungspunkt
|
||||
ist nur, dass CAPsMANs dynamische Objekte für GC unsichtbar sind (der Grund von 2026-07-22, und der gilt).
|
||||
- 🔎 **Aber eine Begründung von damals hält der Prüfung nicht stand.** Der Entscheid nannte als ersten Grund
|
||||
„WLAN dauerhaft instabil, besonders wenn beide APs laufen". **Das WLAN ist nach dem Standalone-Rebuild
|
||||
weiterhin instabil** — die These „CAPsMAN war die Ursache" ist damit empirisch geschwächt. Die Funde A–E sind
|
||||
Funkparameter; CAPsMAN hätte sie weder verursacht noch geheilt. **Der Rebuild hat ein Symptom umgezogen,
|
||||
keine Ursache beseitigt.**
|
||||
- **Wo GC hier tatsächlich Last war:** es hat diesen Drift **nicht verhindert.** Die Compliance deckt
|
||||
`wifi-steering` ab (seit TP3.3), aber offensichtlich **nicht die Channel-/Inline-Override-Fläche** — sonst wären
|
||||
Fund A und D als Drift aufgeschlagen. Das ist eine **Lücke im Feature-Set, kein Argument gegen GC.**
|
||||
- **Ehrliches Urteil (meine Empfehlung):** GC als SoT **behalten** — es ist das Einzige, was Hand-Tuning davon
|
||||
abhält, sich still zu akkumulieren, und genau das ist hier passiert. Aber: **GC ist kein WLAN-Tuning-Werkzeug.**
|
||||
Der Ausweg ist nicht CAPsMAN, sondern die Parameter **einmal nach Manual richtig** zu setzen und dann mit einer
|
||||
Compliance-Feature auf `/interface/wifi` **festzunageln**. Bei genau 2 APs ist der Kanal-/Leistungsplan eine
|
||||
Einmalentscheidung, kein Laufzeitproblem — der Hauptvorteil von CAPsMAN greift hier also kaum.
|
||||
*(Wenn ein dritter AP dazukäme, wäre die Abwägung neu zu führen.)*
|
||||
|
||||
#### 📋 Umsetzungsreihenfolge (alles via GC, gestaffelt, ap2 zuerst)
|
||||
1. **Fund D** — `channel.*`-Overrides von `w2-iot` entfernen (beide APs identisch). Kleinster Eingriff, klärt
|
||||
Beobachtung 3 und ist Vorbedingung für die Fund-F-Messung.
|
||||
2. **Fund A** — Inline-`channel.*` auf `wifi1`/`wifi2` leeren → 2,4 GHz fällt auf die profilkonformen 20 MHz.
|
||||
3. **Fund B+C** — `ch-5g` auf `width=20/40mhz`, ap1 `frequency=5180`, **ap2 `frequency=5220`** → ap2 bekommt
|
||||
+9 dBm, beide non-DFS Indoor, überlappungsfrei.
|
||||
4. **Fund E** — `access-list` mit `signal-range`-Boden je AP; Schwellen erst nach dem Re-Walk festlegen.
|
||||
5. **Re-Walk + Dead-Spot-Kartierung** (der übernommene TP3.3-Rest) — **erst jetzt**, gegen die korrigierte Basis.
|
||||
Vorher gemessene Werte sind wertlos.
|
||||
6. **Compliance-Feature** auf `/interface/wifi channel` + `/interface/wifi` erweitern, damit A und D nicht
|
||||
wiederkommen.
|
||||
- ⚠️ **`steering=`/Channel-Änderungen re-applien alle VAPs und werfen jeden Client kurz raus** (TP3.3 am
|
||||
2026-08-13 gemessen: ap1 25→2, ap2 7→14). **Nicht während eines Calls deployen.** `/system backup` je AP vorher.
|
||||
- **Abh.:** TP22 ✅ (GC-Deploy-Pipeline). Übernimmt den offenen Rest von **TP3.3**, verwandt **TP3.2** (Coverage-Doku
|
||||
`docs/wifi-p750w-coverage-and-map.md`). **Kein Blocker für TP5/TP6** — läuft parallel.
|
||||
|
||||
### TP16.3 — cloudflared-Reduktion: was der Mesh als Datenpfad kann (und was nicht) ▸ ⏳ **RECHERCHE DURCH (2026-08-17)**, Umsetzung offen
|
||||
> **Christophs Frage (2026-08-17):** „recherchiere, ob unser neuer wg-tunnel/cf mesh als datenpfad für die
|
||||
> server/services genutzt werden kann. die containerpflicht als offizieller weg ist für mich unlogisch."
|
||||
|
||||
- ✅ **Die Container-„Pflicht" gibt es für den privaten Zugang tatsächlich nicht — und wir nutzen sie schon nicht mehr.**
|
||||
CF-Docs (Mesh↔Tunnel-Vergleichstabelle) sind eindeutig: **Mesh** = bidirektional, L3/L4, **TCP+UDP+ICMP**, jeder
|
||||
Teilnehmer bekommt eine Mesh-IP, Connector = `warp-cli` **oder ein nativer WireGuard-Peer** (unser Fall).
|
||||
**Tunnel** = *inbound zum Origin*, Veröffentlichen von Hostnames, Connector = `cloudflared`, Protokolle
|
||||
HTTP/S·TCP·SSH·RDP·SMB **über WebSocket geproxied**. Für „Server hinter dem Node erreichbar machen, die keinen
|
||||
Client laufen lassen können" nennen die Docs ausdrücklich **CIDR-Routes auf dem Mesh-Node** als den Weg —
|
||||
wörtlich für „servers, databases, printers, IoT devices".
|
||||
- 🎯 **Das ist bei uns seit TP16.1 bereits scharf:** die vnet-Route `10.40.0.0/16` zeigt auf `bf-core-mesh`
|
||||
(§4.4, Weg A). **Der gesamte private Datenpfad läuft schon über natives WireGuard auf dem Core, ohne jeden
|
||||
Container.** Und er ist im TP5-Log-Lauf **belegt**, nicht vermutet: 137 Zeilen `in:cf-mesh`, Quelle
|
||||
`100.96.0.1` → Nautobot `.20.30:8080` (62×), NAS `.20.10:6690` (46×), macmini `:22`, NAS `:5000/:5001/:443/:22`,
|
||||
pve `.20.100:8006`, pve-mcp `.20.173:3000`, branch/ap1/ap2 `:22`. **Christophs Instinkt war richtig.**
|
||||
- 🔴 **Wo die Container-Pflicht echt ist — und warum sie nicht willkürlich ist:** für einen **öffentlichen
|
||||
Hostname**, den jemand **ohne** WARP im Browser aufruft, braucht es einen Reverse-Proxy an der Edge. Das ist
|
||||
`cloudflared`. **Achtung Verwechslungsfalle:** Mesh kennt seit 2026-07-02 ebenfalls **Hostname-Routes**, und
|
||||
die können auch *public* hostnames — aber das ist **Egress**: „route that hostname's traffic through the node
|
||||
and egress via the node's public IP". Es **veröffentlicht nichts**. Wer das verwechselt, baut den Public-Strang
|
||||
ab und ist überrascht.
|
||||
- ✅ **Der reale Gewinn ist trotzdem groß, weil die meisten Dienste keinen öffentlichen Hostname brauchen.**
|
||||
Kriterium: **hat der Dienst einen Client, der keinen interaktiven Access-Login kann?** (dieselbe Logik wie der
|
||||
TP16.2-Constraint bei `vw`)
|
||||
| Muss öffentlich bleiben (cloudflared) | Grund | Kann auf Mesh-only |
|
||||
|---|---|---|
|
||||
| `vw` | Bitwarden-Clients, harter TP16.2-Constraint | `pve`, `nautobot`, `portainer`, `grafana` |
|
||||
| `hass` | Companion-App (400-Muster) | `pve-mcp`, `ha-mcp`, `gitea-mcp`, `ds-bf` |
|
||||
| `n8n` | eingehende Webhooks von Dritten | `ccu`, `iobroker`, `z2m25` |
|
||||
| `gitea` | Git-Clients / CI von außen — **zu prüfen** | |
|
||||
→ Für die rechte Spalte ist der Mesh **funktional gleichwertig und operativ einfacher** (keine Ingress-Zeile,
|
||||
kein Connector-Paar, keine HA-Frage). Sie erreicht man ohnehin schon per privater IP.
|
||||
- 📌 **Zwei Nebeneffekte, die den Fall stärken:** (1) die **TP16-HA-Degradierung** (`bf-nas`/`bf-pve` je nur ein
|
||||
Connector) verliert an Gewicht, sobald nur noch die vier Public-Dienste an cloudflared hängen — weniger Dienste
|
||||
pro SPOF; (2) **ICMP + beliebiges UDP** gehen über den Mesh und über cloudflared grundsätzlich nicht (der
|
||||
QUIC-Proxy war genau die Lücke aus TP16.1).
|
||||
- ⚠️ **Grenzen, ehrlich benannt:** (a) der Mesh-Weg setzt **WARP auf dem Client** voraus — für Christophs eigene
|
||||
Geräte gegeben, für Gäste/Fremdgeräte nicht; (b) **IPv6-CIDR-Routes brauchen MASQUE** und funktionieren mit
|
||||
einem WireGuard-Device-Profil **nicht** — deckt sich mit dem v4-only-Entscheid aus TP16.1, wäre aber ein
|
||||
Blocker, falls TP12 später v6 über den Mesh wollte; (c) es bleibt eine **Cloudflare-Abhängigkeit** — der Mesh
|
||||
ersetzt cloudflared, nicht Cloudflare.
|
||||
- **Vorgeschlagener Umsetzungsschnitt (klein anfangen, reversibel):** einen Dienst der rechten Spalte als Probe
|
||||
aus dem CF-Ingress nehmen (Kandidat: `nautobot` — nur Christoph nutzt es, im Mesh-Log mit 62 Treffern der am
|
||||
häufigsten per Mesh angefasste Dienst, und ein Fehlschlag kostet nichts Produktives), eine Woche fahren, dann
|
||||
entscheiden. **Rollback = eine Ingress-Zeile zurück.**
|
||||
- **Abh.:** TP16.1 ✅ (Mesh live), TP16 (Public-Strang + dessen HA-Degradierung), **TP16.2** (der `vw`-Constraint
|
||||
liefert das Entscheidungskriterium). ⚠️ **Berührt TP5:** der Mesh-Verkehr braucht bei deny-by-default eine
|
||||
explizite `forward`-Zeile — s. TP5 Etappe 2.
|
||||
|
||||
### TP-R — Router-Capabilities-Sweep ▸ FERTIG (`docs/research/routeros-capabilities.md`)
|
||||
- **Leitsatz: nativ vor Container, NAS vor Router** (128MB-Flash-Limit).
|
||||
- **Sofort nativ (~0 RAM):** RoMON · Netwatch · Scheduler + Auto-Backup/Mail · SNMP→externes Monitoring · **mDNS-Repeater** · spectral-scan · **802.11r/k/v (Fast-Roaming statt Mesh)** *(die Sweep-Fassung nannte hier CAPsMAN — das ist seit 2026-08-08 abgeschafft; 11r/k/v läuft standalone weiter, s. TP3/TP3.3)* · Back-to-Home/WireGuard.
|
||||
@@ -823,28 +1082,50 @@ FT kaschierte das bisher als „Roaming" statt „schwache Abdeckung".
|
||||
|
||||
## Reihenfolge / Abhängigkeiten
|
||||
|
||||
### 🎯 Kritischer Pfad (Stand 2026-08-16)
|
||||
### 🎯 Kritischer Pfad (Stand 2026-08-17)
|
||||
|
||||
```
|
||||
TP5 (Deny-by-default) ──► TP6 (CAKE) ◄ Projektziel
|
||||
TP5 E1 ✅ ──► TP5 E2 ✅ ──► [mehrtägiges stilles Fenster] ──► TP5 E3 (Drop) ──► TP5 E4 ──► TP6 (CAKE) ◄ Projektziel
|
||||
▲
|
||||
D2: iPhone aus IOT-SSID
|
||||
```
|
||||
|
||||
1. **TP5 — Firewall & Inter-VLAN-Policy.** Runbook liegt (`docs/tp5-deny-by-default-runbook.md`), Etappe 1 ist
|
||||
ein reiner Log-Lauf. **Mit im Paket:** TP7.1 (SSDP-Reflector für die macOS-Sonos-App) — gemeinsam testen,
|
||||
sonst prüft man zweimal dieselbe Strecke. **Keine offenen Blocker.**
|
||||
2. **TP6 — QoS/CAKE + Call-Quality-A/B-Test.** Das eigentliche Projektziel; hängt nur an TP5.
|
||||
1. ✅ **TP5 Etappe 1 — Log-Lauf.** Lief 2026-08-16/17, **43.027 Zeilen** Material.
|
||||
2. ✅ **TP5 Etappe 2 — 11 Whitelist-Regeln** (2026-08-17, ConfigPlan `86fbd528`). Log-Regel verstummt.
|
||||
3. ⏳ **Wartezeit, kein Arbeitsschritt:** das Log muss **mehrere Tage** still bleiben. 70 Sekunden Stille sind
|
||||
keine Aussage — es gibt Geräte, die einmal pro Woche funken. **Das ist das Gate, nicht eine Meinung.**
|
||||
4. 🔜 **TP5 Etappe 3 — Drop scharf schalten.** Vorbedingungen: das stille Fenster **und** D2 (iPhone `.30.201`
|
||||
ins MAIN-SSID, Hands-on Christoph). 🛟 Auto-Revert-Scheduler davor (auf dem Core möglich, `device-mode`
|
||||
erlaubt scheduler — auf den hAPs nicht).
|
||||
5. 🔜 **TP5 Etappe 4 — UNTRUSTED/GUEST Internet-only + MGMT isolieren** (`seal-lan` verengen → schaltet
|
||||
zugleich die 5 toten mDNS-`input`-Regeln scharf). **Mit im Paket:** TP7.1 (SSDP-Reflector für die
|
||||
macOS-Sonos-App) — gemeinsam testen, sonst prüft man zweimal dieselbe Strecke.
|
||||
6. 🔜 **TP6 — QoS/CAKE + Call-Quality-A/B-Test.** Das eigentliche Projektziel; hängt nur an TP5.
|
||||
|
||||
**Eine harte Reihenfolge-Regel dazwischen:** TP5 darf die **DNS-Bypass-Sperre erst schließen, wenn TP23s
|
||||
Ausnahme-Oberfläche steht** — der bisherige Workaround „Client von Hand auf `1.1.1.1`" *ist* genau dieser
|
||||
Bypass. Alles andere aus TP5 ist davon unabhängig und kann vorher laufen.
|
||||
|
||||
⚠️ **Und eine zweite, aus TP16.1/TP16.3:** der Drop braucht `cf-mesh` explizit — steht seit Etappe 2 als
|
||||
`TP5-E2: mesh->LAN` / `LAN->mesh` drin. Ohne diese zwei Zeilen sperrt Etappe 3 den Fernzugang aus, also genau
|
||||
den Weg, über den man den Fehler zurücknehmen wollte.
|
||||
|
||||
### Follow-ups nebenher (blockieren nichts)
|
||||
|
||||
- **TP25 — WLAN-Stabilisierung (NEU 2026-08-17):** Audit durch, **6 Funde** (2,4 GHz fährt 40 MHz statt der
|
||||
profilierten 20; ap2 sendet auf 5 GHz mit **9 statt 18 dBm**, weil ch149 unter ETSI leistungsbegrenzt ist;
|
||||
80 MHz kostet Randabdeckung; unzulässiger Channel-Override auf `w2-iot`; keine `access-list`; 5-Minuten-Takt
|
||||
bei IoT-Trennungen offen). Umsetzung in 6 Schritten, alles via GC. **Übernimmt den offenen Rest von TP3.3.**
|
||||
- **TP16.3 — cloudflared-Reduktion (NEU 2026-08-17):** Recherche durch. Der Mesh **ist** schon der private
|
||||
Datenpfad (im TP5-Log mit 137 Zeilen belegt); Container braucht nur noch der **öffentliche** Ingress.
|
||||
Vorschlag: `nautobot` als Probe aus dem CF-Ingress nehmen.
|
||||
- **DoH-Cloudflare auf `crs326-core`** (heute plain `1.1.1.1`) — ist zugleich TP21.1 TODO 1 **und** TP23 Stufe 1.
|
||||
- **TP24 — DC-USV** (seit 2026-08-16 eigener TP, aus TP15 herausgelöst).
|
||||
- **TP19 — VLAN1-Client-Retirement / cudy-Teardown:** Rest sind Media-Check, pve-`.41.100`, Inventar/DNS und
|
||||
die 5 bekannten Compliance-Drifts (Bring-up-Altlasten).
|
||||
- **TP3.3 — WLAN-Coverage-Kur:** 802.11k/v ist repariert (2026-08-13); offen sind Re-Walk + Dead-Spot-Kartierung.
|
||||
- **TP19 — VLAN1-Client-Retirement / cudy-Teardown:** Rest sind physischer cudy-Ausbau, Media-Check, Inventar/DNS
|
||||
und die HA-Portainer-Integration (`setup_retry`). Die VLAN1-Adressen sind ✅ abgeräumt (2026-08-15/16).
|
||||
- ~~**TP3.3 — WLAN-Coverage-Kur**~~ → **in TP25 aufgegangen** (2026-08-17). 802.11k/v ist repariert (08-13);
|
||||
Re-Walk + Dead-Spot-Kartierung laufen als Schritt 5 von TP25 — und zwar erst **nach** den Funkparameter-Fixes,
|
||||
weil vorher gemessene Werte wertlos sind.
|
||||
- **TP10 —** DDNS-Auto-Updater für `bf4.emsenhuber.net` (auf dem Core möglich, `device-mode` erlaubt scheduler).
|
||||
- **TP14.4 —** CF-Access-Service-Token rotieren.
|
||||
- **Doku-Aufräumen** (`docs/doku-cleanup-session.md`) — Punkte A–D am 2026-08-16 abgearbeitet, E teilweise.
|
||||
@@ -852,8 +1133,10 @@ Bypass. Alles andere aus TP5 ist davon unabhängig und kann vorher laufen.
|
||||
### Nachgelagert / research-getrieben
|
||||
|
||||
**TP8** (Identity/802.1X) · **TP11** (Monitoring) · **TP12** (IPv6) · **TP13** (Botschafts-WLANs) ·
|
||||
**TP16.1** (natives CF-Mesh auf dem Core) · **TP16.2** (Härtung bypass-Dienste) · **TP18** (Garage-Objektspeicher) ·
|
||||
**TP20.1** (Vaultwarden → Platform-PG) · **TP23** (DNS-Policy, s. Regel oben).
|
||||
**TP16.2** (Härtung bypass-Dienste) · **TP18** (Garage-Objektspeicher) · **TP20.1** (Vaultwarden → Platform-PG) ·
|
||||
**TP23** (DNS-Policy, s. Regel oben).
|
||||
*(**TP16.1** stand hier bis 2026-08-17 fälschlich als offen — es ist seit demselben Tag ✅ abgeschlossen und
|
||||
steht unten unter „Durch". Nachfolger ist **TP16.3**, das oben unter Follow-ups läuft.)*
|
||||
|
||||
### ✅ Durch (Fundament — nicht mehr planen, nur nachschlagen)
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ Beispiel: `INFRA→MEDIA` hat 178.142 Pakete auf dem Zähler, stand aber im Snap
|
||||
| # | Frage | Vorschlag |
|
||||
|---|---|---|
|
||||
| **D1** | MAIN→INFRA: welche Dienste? | Beobachtet: NAS `6690`, pve-mcp `3000`, macmini `49152`, `3722`. Vorschlag: **erst mit dem Log-Lauf (Etappe 1) vervollständigen**, dann Whitelist — nicht jetzt raten. |
|
||||
| **D2** | iPhone `.30.201` in IOT | Ins MAIN-SSID holen (sauber) **oder** bewusst als Ausnahme dulden. Empfehlung: umhängen. |
|
||||
| **D2** | ~~iPhone `.30.201` in IOT~~ | ✅ **ENTSCHIEDEN (2026-08-14): ins MAIN-SSID umhängen.** Hands-on bei Christoph (SSID wechseln + `dirtyvader-iot` vergessen lassen). Beleg, dass es dasselbe Telefon ist: die statische Reservierung `10.40.10.196` „iPhone" trägt eine *andere* private MAC — iOS vergibt **pro SSID** eine eigene Private Address. Genau darum wäre eine Whitelist auf `.30.201` instabil. |
|
||||
| **D3** | ~~ICMP-Sweep `.10.82`→IOT~~ | ✅ **ENTSCHIEDEN (2026-08-14): `lanscan.app`, Ad-hoc vom Arbeitsplatz.** Keine Dauerregel — läuft über die **JIT-Admin-Gruppe** (selbstverfallend). Deckt sich mit D4. |
|
||||
| **D4** | Wer darf auf VLAN99-Mgmt? | Vorschlag: nur MAIN (`vlan10`), Rest drop. `seal-lan` entsprechend verengen. |
|
||||
| **D5** | IOT→INFRA-Whitelist | Doku nennt MQTT 1883/8883, HA-API, Influx 8086. Beobachtet real: **`8123` (HA), `5540/udp` (Matter)**. Vorschlag: die beobachteten + MQTT. |
|
||||
@@ -104,19 +104,83 @@ Beispiel: `INFRA→MEDIA` hat 178.142 Pakete auf dem Zähler, stand aber im Snap
|
||||
> Vor **jedem** Push `/system backup` auf dem Core (Regel 3). Und: **nur die Gegenprüfung am Gerät zählt**,
|
||||
> Job- und Plan-Status sind kein Wirksamkeitsnachweis (zweimal belegt, TP21.1/TP22).
|
||||
|
||||
### Etappe 1 — Log-Lauf (blockiert nichts, Dauer: einige Tage)
|
||||
#### Push-Werkzeug + Fallen (aus dem Etappe-1-Rollout, 2026-08-14 am Gerät belegt)
|
||||
|
||||
Eine einzige Regel **ans Ende von `forward`**, `action=log` statt `drop`:
|
||||
Werkzeug: `nautobot/gc-manual-plan.py --device <name> --commands-file <datei> --change-id <id> [--dry-run|--deploy]`.
|
||||
Es legt den manual Plan an, prüft `plan.device` gegen den Namen, gibt frei, deployt und liest
|
||||
**den Plan-Status** zurück (nicht den Job-Status). Kommentar-/Leerzeilen werden abgestreift.
|
||||
|
||||
1. 🔴 **Bindestriche in `name=` werden abgelehnt.** `add name="tp5-remote"` und `add name="tp5-abc"`
|
||||
werfen, `add name="tp5syslog"` geht — **Quoten hilft nicht.** Das hat vier Deploys gekostet, weil die
|
||||
naheliegende Erklärung („`remote=` darf nicht ins selbe `add` wie `target=remote`") *falsch* war:
|
||||
`set remote=… remote-port=…` in einem Statement läuft anstandslos. Bei neuen benannten Objekten
|
||||
also **Namen ohne Bindestrich** wählen, oder das Gegenteil erst beweisen.
|
||||
2. 🔴 **Ein gescheiterter Netmiko-Deploy hinterlässt einen TEIL-Zustand.** Die TP22-Notiz
|
||||
„gescheiterter Deploy = sauberer Fehlschlag" galt dem **NAPALM**-Weg, der scheiterte, *bevor* er das
|
||||
Gerät anfasste. Netmiko schickt Zeile für Zeile und lässt Abgesetztes stehen: der erste Push hier
|
||||
hinterließ Zeile 3+4 ohne 1+2. **Nach jedem Fehlschlag den Ist-Stand am Gerät prüfen.**
|
||||
3. **Keine `print`-Zeilen in einen Config Plan.** Ein `/system identity print` als Kanarienzeile hat die
|
||||
unmittelbar folgende Zeile verschluckt und eine Fehldiagnose erzeugt.
|
||||
4. **Selbstprotokollierende Pläne sind die Diagnosemethode.** Der Deploy-Job liefert nur
|
||||
`E1028: found bad/failed/failure in output` und zeigt den Geräte-Output **nicht**. Jedes Kommando in
|
||||
`:do {…} on-error={ :log info "…" }` wickeln und danach eine Zählzeile
|
||||
`:log info ("… count=" . [:tostr [:len [… find …]]])` setzen — anschließend per `get_log` zeilengenau
|
||||
auslesen. Damit ist Root-Cause-Analyse **ohne Direkt-Write** möglich.
|
||||
|
||||
### Etappe 1 — Log-Lauf (blockiert nichts, Dauer: einige Tage) ▸ 🟢 **SAMMELPHASE LÄUFT (seit 2026-08-16)**
|
||||
|
||||
> Historie: am 2026-08-14 **vor** der Sammelphase pausiert, weil 76 % des Verkehrs `.41.x`-Altlast war.
|
||||
> Nach dem VLAN1-Rückbau (TP19) am 2026-08-16 wieder scharf — `routeros/tp5-etappe1-resume.rsc`.
|
||||
>
|
||||
> ✅ **Abnahme bestanden: `out:bridge` = 0** über ein 10-Minuten-Fenster (Logdatei vorher geleert).
|
||||
> Rate von ~166 auf ~34 Zeilen/min gefallen. Die beobachtete Matrix steht in
|
||||
> `docs/teilprojekte.md` → TP5 und ist ab jetzt das Arbeitsmaterial für Etappe 2.
|
||||
>
|
||||
> **Zwei Regeln stehen damit schon fest und brauchen keinen weiteren Beleg aus dem Log:**
|
||||
> 1. `accept out-interface-list=WAN` — ohne sie nimmt der Drop das ganze Haus vom Netz.
|
||||
> 2. Der **Management-Pfad** `10.40.20.105 → 10.40.99.{2,11,12}:8728` (HA-`mikrotik`-Integrationen)
|
||||
> plus MikroMCP vom Arbeitsplatz — sonst sperrt der Drop die Netzverwaltung aus.
|
||||
> 3. **Same-VLAN-mDNS** (`vlan10 → vlan10`, `5353`, vom Repeater auf dem Core erzeugt) erreicht die
|
||||
> `forward`-Kette und würde von einem blanken Drop getroffen.
|
||||
|
||||
Ausgerollt über Nautobot GC (manual Config Plans, `nautobot/gc-manual-plan.py`), Quelle
|
||||
`routeros/tp5-etappe1-log-lauf.rsc`. Auf dem Gerät:
|
||||
|
||||
```
|
||||
/ip firewall filter add chain=forward action=log log-prefix="TP5-WOULD-DROP" comment="TP5: log-only, Vorstufe zum deny-by-default"
|
||||
/ip firewall filter add chain=forward action=log log-prefix="TP5-WOULD-DROP" \
|
||||
comment="TP5: log-only, Vorstufe zum deny-by-default" out-interface-list="!WAN"
|
||||
```
|
||||
|
||||
Das protokolliert exakt die Pakete, die der spätere Drop treffen würde — inklusive der Dinge, an die
|
||||
niemand denkt (Drucker-Discovery, Backup-Jobs, ein Gerät, das nur einmal pro Woche funkt). **Diese Liste
|
||||
ist die Whitelist**, nicht eine am Schreibtisch ausgedachte. Danach D1/D3/D5 final beantworten.
|
||||
ist die Whitelist**, nicht eine am Schreibtisch ausgedachte. Danach D1/D5 final beantworten.
|
||||
|
||||
⚠️ Log-Ziel vorher setzen (`/system logging`), sonst läuft nur der Speicher-Ringpuffer mit.
|
||||
**Log-Ziel steht:** syslog-ng-Container `tp5-syslog` auf dem Docker-LXC, **`10.40.20.18:514`**,
|
||||
Dateien unter `/opt/tp5-syslog/log/` (`tp5-would-drop.log` gefiltert + Host-Dateien).
|
||||
Auf dem Core: Action `tp5syslog` + `logging add topics=firewall action=tp5syslog`.
|
||||
Disk-Logging auf dem Core scheidet aus (**nur ~3 MB freier Flash**), der Memory-Ring (1000 Zeilen)
|
||||
wickelt sich in Minuten um. `firewall` ist aus dem Memory-Ring genommen (`topics=info,!firewall`),
|
||||
damit der On-Box-Log während des mehrtägigen Laufs für andere Fehlersuche brauchbar bleibt —
|
||||
**am Ende von Etappe 1 auf `topics=info` zurückbauen.**
|
||||
⚠️ Der LXC hat nur ~2,5 GB frei; `/usr/local/bin/tp5-log-guard.sh` (Cron, alle 10 min) kappt bei 500 MB
|
||||
je Datei per Truncate-in-place. Ein vollgelaufenes Dateisystem risse dort auch adguard/cloudflared mit.
|
||||
|
||||
#### 🔴 `out-interface-list="!WAN"` — warum die Regel nicht bare steht
|
||||
|
||||
Bare gefasst fing sie **auch den gesamten Internet-Verkehr** (`out:vlan100`): in einer ruhigen Minute
|
||||
242 Zeilen/min, davon ¼ WAN-bound, unter Last deutlich mehr. LAN→WAN ist aber eine **garantierte**
|
||||
Whitelist-Zeile — ohne sie hat kein VLAN Internet, auch die „Internet-only"-VLANs 50/90 nicht.
|
||||
Es wäre also Rauschen genau in der Matrix, die Etappe 2 ableiten soll.
|
||||
|
||||
**Merkposten für Etappe 3:** der Drop darf aus demselben Grund **nicht** bare ans Kettenende —
|
||||
`accept out-interface-list=WAN` gehört davor, sonst ist das ganze Haus offline. Diese Zeile ist
|
||||
bekannt und braucht keinen Beleg aus dem Log.
|
||||
|
||||
#### Auswertung
|
||||
|
||||
```bash
|
||||
ssh root@10.40.20.100 'pct exec 400 -- grep -o "in:vlan[0-9]* out:[a-z0-9]*" /opt/tp5-syslog/log/tp5-would-drop.log | sort | uniq -c | sort -rn'
|
||||
```
|
||||
|
||||
### Etappe 2 — Whitelists bauen (noch immer ohne Drop)
|
||||
|
||||
|
||||
203
docs/vlan1-rueckbau-howto-manuelle-schritte.md
Normal file
203
docs/vlan1-rueckbau-howto-manuelle-schritte.md
Normal file
@@ -0,0 +1,203 @@
|
||||
# VLAN1-Rückbau — Howto für die manuellen Schritte
|
||||
|
||||
> Stand 2026-08-15. Gegenstück zum Plan „VLAN1-Rückbau: `.41.211` (Core), `.41.100` (pve),
|
||||
> Prometheus-Ziele". Hier steht **nur, was du selbst machen musst** — was ich übernehmen kann,
|
||||
> steht unten unter „Was ich mache".
|
||||
|
||||
---
|
||||
|
||||
## Die eine Regel, die die Reihenfolge bestimmt
|
||||
|
||||
`10.40.41.100` ist derzeit der **einzige lebende VLAN1-Host**, und Home Assistant erreicht pve
|
||||
heute genau darüber. Dieser Pfad existiert nur, weil der Core noch die Adresse `10.40.41.211`
|
||||
trägt und damit die Route zu `10.40.41.0/24` stellt.
|
||||
|
||||
➡️ **Schritt 1 und 2 müssen fertig sein, bevor irgendjemand `.41.100` oder `.41.211` entfernt.**
|
||||
Sonst reißt die laufende pve-Anbindung ab.
|
||||
|
||||
---
|
||||
|
||||
## Schritt 1 — Home Assistant: pve-Integration auf `10.40.20.100`
|
||||
|
||||
**Wo:** HA-Weboberfläche → Einstellungen → Geräte & Dienste → **Proxmox VE** (Kachel heißt heute
|
||||
`10.40.41.100`) → ⋮ → **Neu konfigurieren**. Host auf `10.40.20.100` ändern, Port `8006` bleibt.
|
||||
|
||||
**Warum du und nicht ich:** die Integration hat *keinen* Options-Flow (`supports_options: false`),
|
||||
nur einen Reconfigure-Flow. Der fragt die Proxmox-Zugangsdaten erneut ab — und Passwörter oder
|
||||
API-Token gebe ich grundsätzlich nicht ein. Das ist der Teil, der bei dir bleiben muss.
|
||||
|
||||
**Das Netz ist nachweislich nicht das Problem** (falls es wieder hakt, such nicht dort):
|
||||
|
||||
- `pveproxy` lauscht auf `*:8006`, `pve-firewall` ist *disabled*, keine iptables-Regel,
|
||||
kein `/etc/default/pveproxy`.
|
||||
- `https://10.40.20.100:8006` antwortet aus VLAN10 **und** VLAN20 mit HTTP 200 in ~0,06 s.
|
||||
- HA selbst redet längst problemlos mit VLAN20 und VLAN99: `mqtt` → `10.40.20.108`,
|
||||
`influxdb` → `10.40.20.8`, alle vier `mikrotik`-Integrationen auf `.99.x` sind `loaded`.
|
||||
|
||||
---
|
||||
|
||||
## Schritt 2 — Portainer hängt: `docker system df` auf der NAS ⏳ OFFEN, deine Entscheidung
|
||||
|
||||
> ⚠️ **Korrektur (2026-08-15):** meine erste Erklärung — die tote Umgebung `odroid-m1` — war
|
||||
> **falsch**. Du hast sie entfernt, die Integration hängt weiter. Alle verbliebenen Endpoints
|
||||
> antworten in 0,01–0,16 s. Die Vermutung ist damit widerlegt, nicht nur unbestätigt.
|
||||
|
||||
**Die tatsächliche Ursache, aus dem HA-Debug-Log:**
|
||||
|
||||
```
|
||||
pyportainer.exceptions.PortainerTimeoutError: Timeout error while accessing
|
||||
GET https://10.40.20.126:9443/api/endpoints/14/docker/system/df
|
||||
-> UpdateFailed -> ConfigEntryNotReady -> setup_retry
|
||||
```
|
||||
|
||||
Die HA-Integration ruft beim Setup `docker system df` für **jede** Umgebung auf. Gemessen:
|
||||
|
||||
| Endpoint | `docker system df` |
|
||||
|---|---|
|
||||
| ep2 `pve` | 0,05 s |
|
||||
| **ep14 `nas-bf`** | 🔴 **kam nach 180 s nicht zurück** |
|
||||
| ep20 `macmini` | 0,33 s |
|
||||
| ep21 `nas-fm` | 0,98 s |
|
||||
|
||||
Direkt auf der NAS gemessen (`sudo /usr/local/bin/docker system df`): der Befehl **gibt die Tabelle
|
||||
aus und beendet sich dann nicht** — Exit-Code 124 nach 120 s, obwohl die Daten längst da waren.
|
||||
Die Mengen sind harmlos (25 Images / 13 GB, 21 Container, 10 Volumes / 79 MB), es ist also **kein
|
||||
Größenproblem**, sondern ein hängender Aufruf im dockerd der Synology. Das Container-Listing auf
|
||||
demselben Endpoint dauert 0,16 s — nur `system df` klemmt.
|
||||
|
||||
### Container-Manager-Neustart durchgeführt (2026-08-15) — hat den Hänger behoben, reicht aber nicht
|
||||
|
||||
`synopkg stop/start ContainerManager` (Binary liegt unter `/usr/syno/bin/synopkg`, **nicht** im
|
||||
sudo-PATH). Ergebnis:
|
||||
|
||||
- ✅ **Alle 14 Container aus der Baseline sind zurück**, keiner fehlt. Zusätzlich kam `hms-mqtt`
|
||||
hoch, der vorher nicht lief (Restart-Policy) — **prüfen, ob der bleiben soll**.
|
||||
- ✅ `docker system df` **beendet sich wieder** (vorher: gab die Tabelle aus und hing dann; rc=124).
|
||||
- ❌ **Aber es ist weiterhin viel zu langsam und schwankt stark:** 33 s → 92 s → 3× über 120 s.
|
||||
`pyportainer` gibt lange vorher auf, die Integration bleibt auf `setup_retry`.
|
||||
|
||||
**Wo die Zeit hingeht — gemessen, nicht vermutet:**
|
||||
|
||||
| Aufruf | Dauer |
|
||||
|---|---|
|
||||
| `docker images -q` | 84 ms |
|
||||
| `docker ps -aq` | 95 ms |
|
||||
| `docker volume ls -q` | 65 ms |
|
||||
| **`docker system df`** | **33–92+ s** |
|
||||
|
||||
Das Auflisten ist trivial schnell; die Zeit geht **vollständig in die Größenberechnung**, also das
|
||||
`du`-artige Durchlaufen der overlay2-/Volume-Verzeichnisse auf den NAS-Platten. Das ist ein
|
||||
struktureller Nachteil dieser Plattform, kein Defekt — und die HA-Integration ruft `system df`
|
||||
für **jede** Umgebung bei **jedem** Update auf.
|
||||
|
||||
### Der aussichtsreichste Weg: eigener Portainer-Benutzer für HA
|
||||
|
||||
Portainer kann Umgebungszugriff pro Benutzer beschränken. Ein HA-eigener Benutzer mit Zugriff auf
|
||||
**ep2, ep20, ep21 — aber nicht ep14** löst das Problem an der Wurzel: die Integration sieht die
|
||||
langsame NAS-Umgebung dann gar nicht.
|
||||
|
||||
**Wo:** Portainer → Users → neuen Benutzer anlegen → Environments → Zugriff auf ep14 entziehen →
|
||||
Access-Token erzeugen → in HA die Portainer-Integration mit diesem Token neu anlegen.
|
||||
|
||||
**Warum du und nicht ich:** Benutzer anlegen und Token erzeugen sind Konto- und Credential-Schritte,
|
||||
die ich grundsätzlich nicht übernehme.
|
||||
|
||||
**Alternativen, ehrlich bewertet:**
|
||||
- *Nichts tun* — die Integration bleibt auf `setup_retry`, stört sonst nichts. Völlig vertretbar.
|
||||
- *Images aufräumen* (6,98 GB / 53 % sind reclaimable) — verkürzt den Durchlauf, aber
|
||||
ob es unter das `pyportainer`-Limit kommt, ist **offen**. Ich würde nicht darauf setzen.
|
||||
- *ep14 ganz aus Portainer nehmen* — kostet die NAS-Verwaltung, schlechter Tausch.
|
||||
|
||||
---
|
||||
|
||||
## Schritt 3 — ioBroker: NAS-Ziel korrigieren
|
||||
|
||||
**Wo:** ioBroker auf `10.40.20.107` (LXC 101 `iob-master`), in der betroffenen Adapter-Instanz.
|
||||
`10.40.41.10:8080` → **`10.40.20.10:8080`** (die NAS unter ihrer aktuellen Adresse).
|
||||
|
||||
Das steckt in der Adapterkonfiguration, nicht in einer Datei, die ich von außen sicher ändern kann.
|
||||
|
||||
---
|
||||
|
||||
## Schritt 4 — Entscheidung: die 11 gestoppten VLAN1-LXCs
|
||||
|
||||
Auf pve stehen 11 **gestoppte** Container mit VLAN1-Adressen und `gw=10.40.41.254` — das ist ap1s
|
||||
abgeschaltete Sekundär-IP, dieses Gateway existiert nicht mehr:
|
||||
|
||||
| LXC | Name | alte IP |
|
||||
|---|---|---|
|
||||
| 103 | minarca | `.41.114` |
|
||||
| 104 | alpine-grafana | `.41.109` |
|
||||
| 109 | node-red | `.41.119` |
|
||||
| 115 | hms-mqtt-publisher | `.41.124` |
|
||||
| 120 | adguard-bf1 | `.41.116` |
|
||||
| 121 | adguard-bf2 | `.41.117` |
|
||||
| 128 | nginx-proxy-manager | `.41.123` |
|
||||
| 129 | caddy | `.41.118` |
|
||||
| 130 | pihole1 | `.41.16` |
|
||||
| 131 | pihole2 | `.41.131` |
|
||||
| 201 | openproject | `.41.120` |
|
||||
|
||||
Solange sie stehen, stören sie nichts. **Wer einen davon startet, landet in einem VLAN ohne
|
||||
Gateway.** Je Container zu entscheiden: löschen, oder auf VLAN20 umziehen (`tag=20` + Adresse +
|
||||
`nameserver`). Nichts davon ist dringend — es soll nur nicht aus Versehen passieren.
|
||||
|
||||
Zusätzlich tragen mehrere *laufende* VLAN20-Gäste noch `nameserver: 10.40.41.254` in der
|
||||
LXC-Config. Das greift erst beim nächsten Start neu, ist also eine stille Zeitbombe für später.
|
||||
|
||||
---
|
||||
|
||||
## Was ich gemacht habe ✅ (2026-08-15)
|
||||
|
||||
1. **pve `10.40.41.100` entfernt.** `/etc/network/interfaces`: Adresszeile raus,
|
||||
`iface vmbr0 inet static` → `inet manual`; Bridge-Parameter unangetastet. Angewendet per
|
||||
`ip addr del` **ohne** `ifreload -a`. Backup `/root/interfaces.bak-tp19-20260815-183045`.
|
||||
Nachher: nur noch `vmbr0.20` trägt eine IP, keine `41.0/24`-Route, **alle 9 Gäste weiter
|
||||
`running`**, `pvesm status` alle aktiv, SSH-Sitzung überlebt.
|
||||
2. **Core `10.40.41.211` entfernt** über Nautobot GC (`routeros/tp19-core-vlan1-address-remove.rsc`),
|
||||
Backup `core-pre-tp19-vlan1-addr-20260815.backup`. Nachher: keine Adresse auf `bridge`, keine
|
||||
`.41`-Route, Mgmt über `.99.1` **und** `10.40.10.1` intakt.
|
||||
**Compliance 17/17 grün** — der letzte offene Drift auf dem Core ist damit weg.
|
||||
3. **Prometheus bereinigt.** Der pauschale `41`→`20`-Ersatz hatte 6 Jobs auf Adressen gesetzt,
|
||||
die es nicht gibt. Ist-Zustand gemessen statt angenommen — **nur 2 Jobs liefern echte Metriken**:
|
||||
|
||||
| Job | Befund | Ergebnis |
|
||||
|---|---|---|
|
||||
| `grafana` `10.40.20.109:3000` | 200, echte Metriken | ✅ aktiv |
|
||||
| `n8n` `10.40.20.167:5678` | 200, echte Metriken | ✅ aktiv |
|
||||
| `gitea` | `.20.157:3000/` gibt 200, aber `/metrics` ist in Gitea **nicht aktiviert** | stillgelegt |
|
||||
| `vaultwarden` | `/metrics` → **404**, exportiert nativ keine Prometheus-Metriken | stillgelegt |
|
||||
| `portainer` | `/api/status` → 200, liefert aber **JSON statt Prometheus-Format** | stillgelegt |
|
||||
| `node`, `alertmanager`, `qdrant` | Container auf der NAS **exited** | stillgelegt |
|
||||
| `pihole` | abgewählt (TP23 = AdGuard); `.20.23` ist ein fremder Dienst | stillgelegt |
|
||||
|
||||
Alle acht **auskommentiert mit Begründung im File**, dazu der `alerting:`-Block (sonst bliebe ein
|
||||
leerer alertmanagers-Eintrag stehen, der Schärfe vortäuscht). Backup
|
||||
`prometheus.yml.bak-20260815`. Nach Reload: **3 aktive Ziele, alle `up`**.
|
||||
|
||||
🔴 **Falle für das nächste Mal — die Datei ist nicht mit dem Login-User schreibbar.**
|
||||
`prometheus.yml` gehört `65534:65534`; das *Verzeichnis* gehört `adm.christoph`. Ein
|
||||
`cat > datei` scheitert an „Permission denied", während ein `cp` daneben klappt — was leicht den
|
||||
Eindruck erweckt, der Schreibvorgang sei durchgegangen. **Schreiben nur per `sudo tee`, und
|
||||
danach per `md5sum` gegen die lokale Fassung prüfen**, nicht der Erfolgsmeldung der Shell trauen.
|
||||
|
||||
---
|
||||
|
||||
## Abnahme
|
||||
|
||||
- pve: `ip -4 addr show vmbr0` ohne `.41`, `ip route` ohne `41.0/24`, `pct list` weiter 9× running.
|
||||
- Core: keine `.41`-Adresse, Mgmt über `.99.1` **und** `10.40.10.1` erreichbar.
|
||||
- Prometheus: `http://10.40.20.151:9090/api/v1/targets` — alle aktiven Ziele `up`, kein `10.40.41.x`.
|
||||
- HA: `proxmoxve` und `portainer` beide auf `loaded`.
|
||||
- **Der eigentliche Test:** TP5-Log-Regel kurz einschalten, 5 Minuten laufen lassen, `out:bridge`
|
||||
muss auf **0 Zeilen** stehen. Vorher waren das 76 % des gesamten Inter-VLAN-Verkehrs.
|
||||
Danach ist TP5 Etappe 1 sauber neu startbar.
|
||||
|
||||
---
|
||||
|
||||
## Nebenbefund
|
||||
|
||||
Im HA-Log stehen 79 abgelehnte Anmeldeversuche auf `/api/websocket` von `90.146.33.177` —
|
||||
das ist **eure eigene öffentliche IP**, der Verkehr kommt also über den CF-Tunnel herein.
|
||||
Vermutlich der ha-mcp-Server mit einem alten Token vor dem Neustart. Wenn die Zahl jetzt nicht
|
||||
weiter steigt, war es genau das; wenn doch, lohnt ein zweiter Blick.
|
||||
197
nautobot/gc-manual-plan.py
Normal file
197
nautobot/gc-manual-plan.py
Normal file
@@ -0,0 +1,197 @@
|
||||
#!/usr/bin/env python3
|
||||
r"""Manuellen Golden-Config-Plan anlegen, freigeben und deployen.
|
||||
|
||||
Der von der Governance (TP22) vorgeschriebene Weg fuer Geraeteaenderungen:
|
||||
feature-/manual-scoped, **nie** "full intended" — ein Voll-Push schriebe
|
||||
`<<REDACTED>>`-Sektionen woertlich aufs Geraet (WLAN-PSKs, WG-Privkey).
|
||||
|
||||
python3 nautobot/gc-manual-plan.py --device crs326-core \
|
||||
--commands-file /pfad/zu/commands.rsc --change-id "TP5-Etappe1" --dry-run
|
||||
python3 nautobot/gc-manual-plan.py --device crs326-core \
|
||||
--commands-file /pfad/zu/commands.rsc --change-id "TP5-Etappe1" --deploy
|
||||
|
||||
Ablauf: Job "Generate Config Plans" (plan_type=manual) -> Plan auf Approved
|
||||
-> Job "Deploy Config Plans". Dazwischen wird jeweils auf den JobResult gewartet.
|
||||
|
||||
ZWEI TP22-LEHREN SIND HIER EINGEBAUT
|
||||
------------------------------------
|
||||
1. **Job-Status ist kein Wirksamkeitsnachweis.** Der Deploy-Job meldete schon
|
||||
SUCCESS, waehrend der Plan auf Failed stand. Das Skript liest darum nach dem
|
||||
Deploy den *Plan*-Status zurueck und richtet seinen Exit-Code danach.
|
||||
Die eigentliche Abnahme bleibt trotzdem die Gegenpruefung am Geraet.
|
||||
2. **Geraete werden einzeln per Name aufgeloest**, nie positional aus einer
|
||||
Sammelabfrage. Nautobot sortiert Sammelabfragen alphabetisch; eine positionale
|
||||
Zuordnung hat einen Deploy schon mal ans falsche Geraet geschickt.
|
||||
"""
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import pathlib
|
||||
import sys
|
||||
import time
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
|
||||
NB = os.environ.get("NAUTOBOT_URL", "http://10.40.20.30:8080")
|
||||
GEN_JOB = "f93bfa53-2332-4fa2-a6ab-5921c802fcee" # Generate Config Plans
|
||||
DEPLOY_JOB = "31c3f093-eeec-43fa-ba4a-0aed2f3c67aa" # Deploy Config Plans
|
||||
|
||||
|
||||
def token():
|
||||
t = os.environ.get("NAUTOBOT_TOKEN")
|
||||
if not t:
|
||||
raise SystemExit("NAUTOBOT_TOKEN nicht gesetzt "
|
||||
"(steht in docs/nas-vlan20/stacks/210-nautobot.yml, gitignored)")
|
||||
return t
|
||||
|
||||
|
||||
def api(path, method="GET", payload=None):
|
||||
req = urllib.request.Request(
|
||||
f"{NB}{path}",
|
||||
data=json.dumps(payload).encode() if payload is not None else None,
|
||||
method=method,
|
||||
headers={"Authorization": f"Token {token()}",
|
||||
"Content-Type": "application/json",
|
||||
"Accept": "application/json"},
|
||||
)
|
||||
try:
|
||||
with urllib.request.urlopen(req, timeout=60) as resp:
|
||||
raw = resp.read()
|
||||
return json.loads(raw) if raw else {}
|
||||
except urllib.error.HTTPError as e:
|
||||
sys.stderr.write(f"HTTP {e.code} auf {method} {path}\n{e.read().decode()[:2000]}\n")
|
||||
raise
|
||||
|
||||
|
||||
def resolve_device(name):
|
||||
"""Einzeln per Name — siehe Kopfkommentar, Lehre 2."""
|
||||
res = api(f"/api/dcim/devices/?name={name}")["results"]
|
||||
if len(res) != 1:
|
||||
raise SystemExit(f"Device {name!r}: {len(res)} Treffer statt genau 1")
|
||||
return res[0]["id"]
|
||||
|
||||
|
||||
def status_id(name):
|
||||
res = api(f"/api/extras/statuses/?content_types=nautobot_golden_config.configplan&name={name}")["results"]
|
||||
if len(res) != 1:
|
||||
raise SystemExit(f"ConfigPlan-Status {name!r}: {len(res)} Treffer statt genau 1")
|
||||
return res[0]["id"]
|
||||
|
||||
|
||||
def wait_job(job_result_id, label, timeout=900):
|
||||
"""Pollt bis der JobResult terminal ist. Gibt den finalen Status zurueck."""
|
||||
deadline = time.time() + timeout
|
||||
last = None
|
||||
while time.time() < deadline:
|
||||
jr = api(f"/api/extras/job-results/{job_result_id}/")
|
||||
st = (jr.get("status") or {}).get("value") or jr.get("status")
|
||||
if st != last:
|
||||
print(f" {label}: {st}")
|
||||
last = st
|
||||
if st in ("SUCCESS", "FAILURE", "ERRORED", "REVOKED"):
|
||||
return st
|
||||
time.sleep(5)
|
||||
raise SystemExit(f"{label}: Timeout nach {timeout}s")
|
||||
|
||||
|
||||
def job_log(job_result_id, levels=("error", "warning", "failure")):
|
||||
try:
|
||||
logs = api(f"/api/extras/job-log-entries/?job_result={job_result_id}&limit=200")["results"]
|
||||
except Exception:
|
||||
return
|
||||
for e in logs:
|
||||
if (e.get("log_level") or "").lower() in levels:
|
||||
print(f" [{e.get('log_level')}] {e.get('message')}")
|
||||
|
||||
|
||||
def main():
|
||||
p = argparse.ArgumentParser()
|
||||
p.add_argument("--device", required=True)
|
||||
p.add_argument("--commands-file", required=True)
|
||||
p.add_argument("--change-id", default="")
|
||||
p.add_argument("--change-url", default="")
|
||||
p.add_argument("--deploy", action="store_true",
|
||||
help="nach dem Anlegen freigeben und ausrollen")
|
||||
p.add_argument("--dry-run", action="store_true",
|
||||
help="nur zeigen, was gepusht wuerde — legt keinen Plan an")
|
||||
args = p.parse_args()
|
||||
|
||||
# Kommentar- und Leerzeilen fliegen raus: der Plan-config_set geht 1:1 per
|
||||
# netmiko an die RouterOS-Konsole, dort haben Doku-Zeilen nichts verloren.
|
||||
# Die kommentierte .rsc bleibt das lesbare Artefakt im Repo.
|
||||
raw = pathlib.Path(args.commands_file).read_text()
|
||||
commands = "\n".join(l for l in (x.rstrip() for x in raw.splitlines())
|
||||
if l.strip() and not l.lstrip().startswith("#"))
|
||||
if not commands:
|
||||
raise SystemExit("commands-file enthaelt keine Kommandozeilen")
|
||||
|
||||
print(f" Geraet: {args.device}")
|
||||
print(f" Change: {args.change_id or '(keine)'}")
|
||||
print(f" Kommandos ({len(commands.splitlines())} Zeilen):")
|
||||
for line in commands.splitlines():
|
||||
print(f" | {line}")
|
||||
|
||||
if args.dry_run:
|
||||
print("\n DRY-RUN — kein Plan angelegt, nichts gepusht.")
|
||||
return
|
||||
|
||||
device_id = resolve_device(args.device)
|
||||
print(f"\n Device-UUID: {device_id}")
|
||||
|
||||
known = {r["id"] for r in api(f"/api/plugins/golden-config/config-plan/?device_id={device_id}&limit=200")["results"]}
|
||||
|
||||
print(" -> Generate Config Plans (plan_type=manual)")
|
||||
run = api(f"/api/extras/jobs/{GEN_JOB}/run/", "POST", {"data": {
|
||||
"device": [device_id],
|
||||
"plan_type": "manual",
|
||||
"commands": commands,
|
||||
"change_control_id": args.change_id,
|
||||
"change_control_url": args.change_url,
|
||||
}})
|
||||
jr = run.get("job_result", run).get("id")
|
||||
st = wait_job(jr, "generate")
|
||||
job_log(jr)
|
||||
if st != "SUCCESS":
|
||||
raise SystemExit(f"Plan-Erzeugung fehlgeschlagen: {st}")
|
||||
|
||||
plans = api(f"/api/plugins/golden-config/config-plan/?device_id={device_id}&limit=200")["results"]
|
||||
new = [r for r in plans if r["id"] not in known]
|
||||
if len(new) != 1:
|
||||
raise SystemExit(f"Erwartet genau 1 neuen Plan, gefunden: {len(new)}")
|
||||
plan = new[0]
|
||||
print(f" Plan angelegt: {plan['id']}")
|
||||
|
||||
# Gegenprobe, dass der Plan wirklich an diesem Geraet haengt (Lehre 2).
|
||||
plan_dev = api(f"/api/plugins/golden-config/config-plan/{plan['id']}/?depth=1")["device"]
|
||||
assert plan_dev["name"] == args.device, f"Plan haengt an {plan_dev['name']}, nicht an {args.device}"
|
||||
print(f" Plan.device verifiziert: {plan_dev['name']}")
|
||||
|
||||
if not args.deploy:
|
||||
print("\n Plan liegt bereit (nicht freigegeben). Mit --deploy ausrollen.")
|
||||
return
|
||||
|
||||
print(" -> Plan auf Approved")
|
||||
api(f"/api/plugins/golden-config/config-plan/{plan['id']}/", "PATCH",
|
||||
{"status": status_id("Approved")})
|
||||
|
||||
print(" -> Deploy Config Plans")
|
||||
run = api(f"/api/extras/jobs/{DEPLOY_JOB}/run/", "POST", {"data": {
|
||||
"config_plan": [plan["id"]],
|
||||
"fail_job_on_task_failure": True,
|
||||
}})
|
||||
jr = run.get("job_result", run).get("id")
|
||||
st = wait_job(jr, "deploy")
|
||||
job_log(jr)
|
||||
|
||||
# Lehre 1: nicht dem Job glauben, den Plan-Status lesen.
|
||||
final = api(f"/api/plugins/golden-config/config-plan/{plan['id']}/?depth=1")
|
||||
plan_status = (final.get("status") or {}).get("name")
|
||||
print(f"\n Job-Status: {st}")
|
||||
print(f" Plan-Status: {plan_status} <- der zaehlt")
|
||||
if plan_status != "Completed":
|
||||
raise SystemExit(f"Deploy nicht sauber durch (Plan: {plan_status})")
|
||||
print("\n Plan Completed. Abnahme trotzdem erst nach Gegenpruefung am Geraet.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
21
routeros/tp19-core-vlan1-address-remove.rsc
Normal file
21
routeros/tp19-core-vlan1-address-remove.rsc
Normal file
@@ -0,0 +1,21 @@
|
||||
# TP19 — VLAN1-Bring-up-Adresse vom Core entfernen.
|
||||
# Ausgerollt 2026-08-15 ueber Nautobot GC (manual Config Plan), Backup davor:
|
||||
# core-pre-tp19-vlan1-addr-20260815.backup
|
||||
#
|
||||
# `10.40.41.211/24` auf `bridge` (Kommentar TP15-bringup-vlan1) war die letzte
|
||||
# .41-Spur auf dem Core und der letzte offene Compliance-Drift (ip-address).
|
||||
# Vorher geprueft: keine DNS-Statics, kein DHCP-Server auf `bridge`, kein Netwatch,
|
||||
# keine Address-Lists mit .41; `bridge` ist NICHT Mitglied der LAN-Interface-Liste.
|
||||
# Mgmt laeuft ueber .99.1 (+ Fallback 10.40.10.1), beides unberuehrt.
|
||||
#
|
||||
# ERWARTETE NEBENWIRKUNG: die dynamische Connected-Route 10.40.41.0/24 verschwindet
|
||||
# mit der Adresse. Das ist gewollt — Restverkehr nach VLAN1 scheitert danach sofort
|
||||
# statt in einen Timeout zu laufen.
|
||||
#
|
||||
# Reihenfolge war bindend und ist erfuellt: HA zeigt auf 10.40.20.100 (Integration
|
||||
# `loaded`), pve hat 10.40.41.100 nicht mehr, Prometheus/ioBroker sind umgezogen.
|
||||
#
|
||||
# Selbstprotokollierend — der Deploy-Job zeigt den Geraete-Output nicht (E1028).
|
||||
|
||||
:do { /ip address remove [find address="10.40.41.211/24"] } on-error={ :log info "tp19: remove hat geworfen" }
|
||||
:log info ("tp19: ENDE rest-41-adressen=" . [:tostr [:len [/ip address find address~"10.40.41."]]] . " rest-41-routen=" . [:tostr [:len [/ip route find dst-address~"10.40.41."]]])
|
||||
74
routeros/tp5-etappe1-log-lauf.rsc
Normal file
74
routeros/tp5-etappe1-log-lauf.rsc
Normal file
@@ -0,0 +1,74 @@
|
||||
# TP5 Etappe 1 — Log-Lauf auf crs326-core. Blockiert NICHTS.
|
||||
# Ausgerollt 2026-08-14 ueber Nautobot GC als manual Config Plans (Governance TP22),
|
||||
# nicht per Direkt-Write. Backup davor: core-pre-tp5-etappe1-20260814.backup
|
||||
#
|
||||
# Diese Datei bildet den AUSGEROLLTEN Endzustand ab. Der Weg dorthin brauchte
|
||||
# mehrere Anlaeufe; die Lehren stehen unten, damit Etappe 2-4 sie nicht wiederholen.
|
||||
# Push: python3 nautobot/gc-manual-plan.py --device crs326-core \
|
||||
# --commands-file routeros/tp5-etappe1-log-lauf.rsc --change-id TP5-Etappe1 --deploy
|
||||
|
||||
# --- 1) Syslog-Ziel ---------------------------------------------------------
|
||||
# Der Core hat nur ~3 MB freien Flash -> Disk-Logging faellt aus (Platz + Flash-Verschleiss),
|
||||
# und der Memory-Ring fasst 1000 Zeilen, den wickelt der Log-Lauf in Minuten um.
|
||||
# Kollektor: syslog-ng auf dem Docker-LXC, 10.40.20.18:514 (Container `tp5-syslog`,
|
||||
# Config /opt/tp5-syslog/config/syslog-ng.conf, Logs /opt/tp5-syslog/log/).
|
||||
# ACHTUNG Name ohne Bindestrich — s. Lehre 1.
|
||||
:do { /system logging action add name="tp5syslog" target=remote } on-error={ :log info "tp5: action add hat geworfen" }
|
||||
:do { /system logging action set [find name="tp5syslog"] remote=10.40.20.18 remote-port=514 } on-error={ :log info "tp5: action set hat geworfen" }
|
||||
|
||||
# --- 2) firewall-Topic an den Kollektor -------------------------------------
|
||||
:do { /system logging add action="tp5syslog" topics=firewall } on-error={ :log info "tp5: logging rule hat geworfen" }
|
||||
|
||||
# --- 3) firewall aus dem Memory-Ring nehmen ---------------------------------
|
||||
# Sonst besteht der 1000-Zeilen-Puffer tagelang zu 100 % aus TP5-Zeilen und der
|
||||
# On-Box-Log ist fuer jede andere Fehlersuche wertlos — genau dann, wenn man ihn braucht.
|
||||
# Matcher live geprueft: topics=info trifft NICHT (Listen-Property), topics~"info" trifft genau 1.
|
||||
# Rueckbau am Ende von Etappe 1: topics=info
|
||||
/system logging set [find topics~"info" and action=memory] topics=info,!firewall
|
||||
|
||||
# --- 4) Die Log-Regel ans ENDE der forward-Kette ----------------------------
|
||||
# action=log ist nicht-terminierend: das Paket laeuft weiter und faellt danach aus
|
||||
# der Kette in die Default-Policy (accept). Es wird nichts blockiert.
|
||||
/ip firewall filter add action=log chain=forward comment="TP5: log-only, Vorstufe zum deny-by-default" log-prefix="TP5-WOULD-DROP"
|
||||
|
||||
# --- 5) Einengung auf Nicht-WAN --------------------------------------------
|
||||
# Der erste Lauf zeigte, dass die Regel auch saemtlichen Internet-Verkehr faengt
|
||||
# (out:vlan100) — bei 242 Zeilen/min war ein Viertel davon WAN-bound, unter Last mehr.
|
||||
# LAN->WAN ist eine GARANTIERTE Whitelist-Zeile (ohne sie hat kein VLAN Internet,
|
||||
# auch die "Internet-only"-VLANs 50/90 nicht), also reines Rauschen fuer die Matrix,
|
||||
# die Etappe 2 ableiten soll.
|
||||
# 🔴 MERKPOSTEN FUER ETAPPE 3: der spaetere drop DARF NICHT bare ans Kettenende —
|
||||
# davor gehoert `accept out-interface-list=WAN`, sonst ist das ganze Haus offline.
|
||||
# Diese Zeile ist bekannt und muss nicht aus dem Log wiederentdeckt werden.
|
||||
/ip firewall filter set [find comment="TP5: log-only, Vorstufe zum deny-by-default"] out-interface-list="!WAN"
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# LEHREN AUS DEM ROLLOUT (jede am Geraet belegt, nicht vermutet)
|
||||
# ===========================================================================
|
||||
#
|
||||
# 1) 🔴 BINDESTRICHE IN `name=` WERDEN ABGELEHNT — der teuerste Fund.
|
||||
# /system logging action add name="tp5-remote" target=remote -> wirft
|
||||
# /system logging action add name="tp5-abc" target=remote -> wirft
|
||||
# /system logging action add name="tp5syslog" target=remote -> geht
|
||||
# Quoten hilft NICHT. Isoliert per :do/on-error-Plan mit Zaehler-Checkpoints.
|
||||
# Zwischenzeitlich hatte ich das faelschlich der Reihenfolge `target=`/`remote=`
|
||||
# im selben add-Statement zugeschrieben — diese Erklaerung ist WIDERLEGT
|
||||
# (`set remote=... remote-port=...` in einem Statement laeuft anstandslos).
|
||||
#
|
||||
# 2) 🔴 EIN GESCHEITERTER NETMIKO-DEPLOY HINTERLAESST EINEN TEIL-ZUSTAND.
|
||||
# Die TP22-Notiz "gescheiterter Deploy = sauberer Fehlschlag" galt dem NAPALM-Weg,
|
||||
# der scheiterte, BEVOR er das Geraet anfasste. Netmiko schickt Zeile fuer Zeile
|
||||
# und laesst Abgesetztes stehen: der erste Push hier hinterliess Zeile 3+4 auf dem
|
||||
# Geraet, ohne 1+2. **Nach jedem Fehlschlag den Geraete-Ist-Stand pruefen.**
|
||||
#
|
||||
# 3) KEINE `print`-ZEILEN IN EINEN CONFIG PLAN. Ein `/system identity print` als
|
||||
# Kanarienzeile hat die unmittelbar folgende Zeile verschluckt und eine
|
||||
# Fehldiagnose erzeugt. Config Plans enthalten nur schreibende Kommandos.
|
||||
#
|
||||
# 4) SELBSTPROTOKOLLIERENDE PLAENE SIND DIE DIAGNOSE-METHODE DER WAHL.
|
||||
# Der Deploy-Job liefert nur "E1028: found bad/failed/failure in output" und
|
||||
# zeigt den Geraete-Output NICHT. Wickelt man jedes Kommando in
|
||||
# `:do {...} on-error={ :log info "..." }` und setzt danach eine Zaehlzeile
|
||||
# `:log info ("... count=" . [:tostr [:len [... find ...]]])`, liest man das
|
||||
# Ergebnis anschliessend per get_log zeilengenau aus — ohne Direkt-Write.
|
||||
32
routeros/tp5-etappe1-pause.rsc
Normal file
32
routeros/tp5-etappe1-pause.rsc
Normal file
@@ -0,0 +1,32 @@
|
||||
# TP5 Etappe 1 — PAUSE (User-Entscheid 2026-08-14).
|
||||
# Grund: erst die .41.x -> .20.x-Migration fertigstellen (Prometheus-Scrape-Ziele,
|
||||
# HA-pve-Integration). Daten, die davor gesammelt werden, gelten danach nicht mehr —
|
||||
# 76 % des Inter-VLAN-Verkehrs waren genau dieses Altlast-Rauschen.
|
||||
#
|
||||
# Push: python3 nautobot/gc-manual-plan.py --device crs326-core \
|
||||
# --commands-file routeros/tp5-etappe1-pause.rsc --change-id TP5-Etappe1-Pause --deploy
|
||||
|
||||
# 1) Log-Regel stilllegen. Bleibt als Objekt stehen (Kommentar = Idempotenz-Schluessel),
|
||||
# das Wiederanschalten ist damit eine Zeile.
|
||||
:do { /ip firewall filter set [find comment="TP5: log-only, Vorstufe zum deny-by-default"] disabled=yes } on-error={ :log info "tp5p: disable hat geworfen" }
|
||||
|
||||
# 2) Memory-Logging zurueckbauen. Der Ausschluss war nur wegen der Flut noetig;
|
||||
# waehrend der Pause faellt keine an, und der On-Box-Log wird fuer die
|
||||
# Migrationsarbeit wieder gebraucht.
|
||||
:do { /system logging set [find topics~"info" and action=memory] topics=info } on-error={ :log info "tp5p: topics-restore hat geworfen" }
|
||||
|
||||
:log info ("tp5p: ENDE regel-disabled=" . [:tostr [/ip firewall filter get [find comment="TP5: log-only, Vorstufe zum deny-by-default"] disabled]] . " memory-topics=" . [:tostr [/system logging get [find topics~"info" and action=memory] topics]])
|
||||
|
||||
# ===========================================================================
|
||||
# WIEDERAUFNAHME (Etappe 1 fortsetzen)
|
||||
# ===========================================================================
|
||||
# Der Kollektor laeuft weiter (Container `tp5-syslog` auf dem Docker-LXC,
|
||||
# restart=unless-stopped, 10.40.20.18:514) und die Logging-Action `tp5syslog`
|
||||
# samt Regel `topics=firewall` bleibt auf dem Core stehen — beides ist ohne die
|
||||
# Filter-Regel wirkungslos. Zum Fortsetzen genuegen zwei Zeilen:
|
||||
#
|
||||
# /ip firewall filter set [find comment="TP5: log-only, Vorstufe zum deny-by-default"] disabled=no
|
||||
# /system logging set [find topics~"info" and action=memory] topics=info,!firewall
|
||||
#
|
||||
# Vorher aufraeumen, sonst mischt sich Altes unter die neue Sammelphase:
|
||||
# ssh root@10.40.20.100 'pct exec 400 -- sh -c ": > /opt/tp5-syslog/log/tp5-would-drop.log"'
|
||||
26
routeros/tp5-etappe1-resume.rsc
Normal file
26
routeros/tp5-etappe1-resume.rsc
Normal file
@@ -0,0 +1,26 @@
|
||||
# TP5 Etappe 1 — WIEDERAUFNAHME nach der Pause vom 2026-08-14.
|
||||
# Gegenstueck zu routeros/tp5-etappe1-pause.rsc.
|
||||
#
|
||||
# Der Grund fuer die Pause ist weg: die .41.x-Altlasten sind abgeraeumt
|
||||
# (HA -> 10.40.20.100, pve .41.100 entfernt, Core .41.211 entfernt,
|
||||
# Prometheus bereinigt, ioBroker korrigiert). Vorher waren 76 % des
|
||||
# Inter-VLAN-Verkehrs `vlan20 -> bridge`, also genau dieses Rauschen.
|
||||
#
|
||||
# Push: python3 nautobot/gc-manual-plan.py --device crs326-core \
|
||||
# --commands-file routeros/tp5-etappe1-resume.rsc \
|
||||
# --change-id TP5-Etappe1-Resume --deploy
|
||||
# Backup davor: core-pre-tp5-resume-20260815.backup
|
||||
#
|
||||
# ABNAHME danach: `out:bridge` im Kollektor-Log muss auf 0 stehen.
|
||||
# Die Logdatei ist vor dem Scharfschalten geleert worden.
|
||||
|
||||
# 1) Log-Regel wieder scharf. Blockiert nichts: action=log ist nicht-terminierend,
|
||||
# und out-interface-list="!WAN" haelt den Internet-Verkehr draussen.
|
||||
:do { /ip firewall filter set [find comment="TP5: log-only, Vorstufe zum deny-by-default"] disabled=no } on-error={ :log info "tp5r: enable hat geworfen" }
|
||||
|
||||
# 2) firewall wieder aus dem Memory-Ring nehmen. Sonst besteht der 1000-Zeilen-Puffer
|
||||
# waehrend der Sammelphase zu 100 % aus TP5-Zeilen und der On-Box-Log ist fuer
|
||||
# jede andere Fehlersuche wertlos — genau dann, wenn man ihn braucht.
|
||||
:do { /system logging set [find topics~"info" and action=memory] topics=info,!firewall } on-error={ :log info "tp5r: topics hat geworfen" }
|
||||
|
||||
:log info ("tp5r: ENDE disabled=" . [:tostr [/ip firewall filter get [find comment="TP5: log-only, Vorstufe zum deny-by-default"] disabled]] . " memory-topics=" . [:tostr [/system logging get [find topics~"info" and action=memory] topics]])
|
||||
100
routeros/tp5-etappe2-whitelists.rsc
Normal file
100
routeros/tp5-etappe2-whitelists.rsc
Normal file
@@ -0,0 +1,100 @@
|
||||
# TP5 Etappe 2 — Whitelists auf crs326-core.
|
||||
#
|
||||
# Quelle: NICHT geraten, sondern aus 43.027 Zeilen Log-Lauf abgeleitet
|
||||
# (Kollektor 10.40.20.18, Fenster 2026-08-16T17:21 .. 2026-08-17T14:05).
|
||||
# Beobachtete Matrix (in -> out):
|
||||
# 20682 vlan20->vlan99 8082 vlan10->vlan20 7123 vlan20->vlan10
|
||||
# 6238 vlan20->vlan30 306 vlan30->vlan20 237 vlan10->vlan30
|
||||
# 214 vlan10->vlan99 17 vlan10->vlan10 2 vlan30->vlan10
|
||||
# 137 cf-mesh->{vlan20,vlan99}
|
||||
# vlan40/50/90: NULL Inter-VLAN -> Internet-only ist risikofrei (D6).
|
||||
#
|
||||
# Entscheidungen (User 2026-08-17):
|
||||
# D1 = MAIN->INFRA pauschal accept (MAIN ist das Trusted-VLAN, INFRA die
|
||||
# eigene Serverzone; Least-Privilege bleibt bei IOT/UNTRUSTED/GUEST/MGMT).
|
||||
# D4 = MGMT named sources: HA:8728 + Nautobot:22 + vlan10 + cf-mesh, Rest drop.
|
||||
# D5 = IOT->INFRA: beobachtet ist nur 8123; MQTT 1883/8883 als dokumentierte
|
||||
# Absicht mit aufgenommen (Shelly-Push kann jederzeit dazukommen).
|
||||
#
|
||||
# BLOCKIERT NICHTS: ausschliesslich action=accept. Der Drop kommt in Etappe 3.
|
||||
#
|
||||
# Push: python3 nautobot/gc-manual-plan.py --device crs326-core \
|
||||
# --commands-file routeros/tp5-etappe2-whitelists.rsc \
|
||||
# --change-id TP5-Etappe2-Whitelists --deploy
|
||||
# Backup davor: core-pre-tp5-etappe2-20260817.backup
|
||||
#
|
||||
# ABNAHMEKRITERIUM: der Zaehler der Log-Regel muss danach (nahezu) stehen
|
||||
# bleiben. Solange sie Nutzverkehr sieht, ist die Whitelist unvollstaendig —
|
||||
# das ist das Gate fuer Etappe 3.
|
||||
#
|
||||
# ---------------------------------------------------------------------------
|
||||
# WICHTIG — place-before: alle Zeilen muessen VOR die Log-Regel. Sonst laeuft
|
||||
# die Log-Regel weiter voll und das Abnahmekriterium oben ist nicht messbar
|
||||
# (action=log ist nicht-terminierend, funktional waere es egal - messbar nicht).
|
||||
# Alle Adds sind per :if [:len [find comment=...]]=0 idempotent, ein zweiter
|
||||
# Lauf legt also nichts doppelt an. Jede Zeile eigenes on-error (Lehre aus
|
||||
# Etappe 1: ein gescheiterter Netmiko-Deploy hinterlaesst Teil-Zustand).
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# 1) LAN -> WAN. Ohne diese Zeile nimmt der spaetere Drop das ganze Haus vom
|
||||
# Netz, inklusive der "Internet-only"-VLANs 50/90. Bekannt, braucht keinen
|
||||
# Logbeleg, und aus demselben Grund stand schon die Log-Regel auf "!WAN".
|
||||
:do { :if ([:len [/ip firewall filter find comment="TP5-E2: LAN->WAN"]] = 0) do={ /ip firewall filter add chain=forward action=accept out-interface-list=WAN comment="TP5-E2: LAN->WAN" place-before=[/ip firewall filter find comment="TP5: log-only, Vorstufe zum deny-by-default"] } } on-error={ :log info "tp5e2: 01 LAN->WAN warf" }
|
||||
|
||||
# 2) Cloudflare Mesh (TP16.1/TP16.3). 137 Logtreffer belegen den Pfad.
|
||||
# Ohne diese beiden Zeilen sperrt der Drop den kompletten Fernzugang aus —
|
||||
# und zwar genau den, mit dem man den Fehler zuruecknehmen wollte.
|
||||
:do { :if ([:len [/ip firewall filter find comment="TP5-E2: mesh->LAN"]] = 0) do={ /ip firewall filter add chain=forward action=accept in-interface=cf-mesh comment="TP5-E2: mesh->LAN" place-before=[/ip firewall filter find comment="TP5: log-only, Vorstufe zum deny-by-default"] } } on-error={ :log info "tp5e2: 02 mesh->LAN warf" }
|
||||
:do { :if ([:len [/ip firewall filter find comment="TP5-E2: LAN->mesh"]] = 0) do={ /ip firewall filter add chain=forward action=accept out-interface=cf-mesh comment="TP5-E2: LAN->mesh" place-before=[/ip firewall filter find comment="TP5: log-only, Vorstufe zum deny-by-default"] } } on-error={ :log info "tp5e2: 03 LAN->mesh warf" }
|
||||
|
||||
# 3) D1 — MAIN <-> INFRA pauschal. Beobachtet waren 13 Dienste (macmini
|
||||
# udp/3722 Continuity 6234x, NAS 6690 1578x, Nautobot 8080, AirPlay 7000,
|
||||
# pve-mcp 3000, ssh auf pve/NAS/macmini, Ollama 11434, ...). Die
|
||||
# Rueckrichtung braucht eine eigene Zeile, weil Continuity je Richtung
|
||||
# eigene Flows oeffnet (7123 "new" aus vlan20).
|
||||
:do { :if ([:len [/ip firewall filter find comment="TP5-E2: MAIN->INFRA"]] = 0) do={ /ip firewall filter add chain=forward action=accept in-interface=vlan10 out-interface=vlan20 comment="TP5-E2: MAIN->INFRA" place-before=[/ip firewall filter find comment="TP5: log-only, Vorstufe zum deny-by-default"] } } on-error={ :log info "tp5e2: 04 MAIN->INFRA warf" }
|
||||
:do { :if ([:len [/ip firewall filter find comment="TP5-E2: INFRA->MAIN"]] = 0) do={ /ip firewall filter add chain=forward action=accept in-interface=vlan20 out-interface=vlan10 comment="TP5-E2: INFRA->MAIN" place-before=[/ip firewall filter find comment="TP5: log-only, Vorstufe zum deny-by-default"] } } on-error={ :log info "tp5e2: 05 INFRA->MAIN warf" }
|
||||
|
||||
# 4) INFRA -> IOT. HA (10.40.20.105) pollt ~22 Shellys auf tcp/80, 6238 Zeilen.
|
||||
# Richtungsasymmetrisch gewollt: INFRA darf IOT anfassen, nicht umgekehrt.
|
||||
:do { :if ([:len [/ip firewall filter find comment="TP5-E2: INFRA->IOT"]] = 0) do={ /ip firewall filter add chain=forward action=accept in-interface=vlan20 out-interface=vlan30 comment="TP5-E2: INFRA->IOT" place-before=[/ip firewall filter find comment="TP5: log-only, Vorstufe zum deny-by-default"] } } on-error={ :log info "tp5e2: 06 INFRA->IOT warf" }
|
||||
|
||||
# 5) D5 — IOT -> INFRA, nur Dienste. Beobachtet: 10.40.30.249 -> HA:8123 (203x).
|
||||
# MQTT mit drin, weil die Doku es als Absicht nennt und ein Shelly-Push
|
||||
# jederzeit dazukommen kann. Influx 8086 NICHT: nie beobachtet, und der
|
||||
# Weg dorthin laeuft ueber HA.
|
||||
:do { :if ([:len [/ip firewall filter find comment="TP5-E2: IOT->INFRA Dienste"]] = 0) do={ /ip firewall filter add chain=forward action=accept in-interface=vlan30 out-interface=vlan20 protocol=tcp dst-port=8123,1883,8883 comment="TP5-E2: IOT->INFRA Dienste" place-before=[/ip firewall filter find comment="TP5: log-only, Vorstufe zum deny-by-default"] } } on-error={ :log info "tp5e2: 07 IOT->INFRA warf" }
|
||||
|
||||
# 6) D4 — MGMT (vlan99). Drei named sources, sonst nichts:
|
||||
# a) MAIN komplett = Arbeitsplatz (.10.82 -> ssh/80/443 auf branch/ap1/ap2)
|
||||
# b) HA .20.105:8728 = mikrotik-Integration, 20.667 Polls. Ohne diese Zeile
|
||||
# brechen die HA-Integrationen.
|
||||
# c) Nautobot .20.30:22 = Netmiko-Deploy der Golden Config. Ohne diese Zeile
|
||||
# sperrt sich TP22 selbst aus — der Weg, ueber den dieser Push laeuft.
|
||||
# cf-mesh ist bereits durch Zeile 2 gedeckt.
|
||||
:do { :if ([:len [/ip firewall filter find comment="TP5-E2: MAIN->MGMT"]] = 0) do={ /ip firewall filter add chain=forward action=accept in-interface=vlan10 out-interface=vlan99 comment="TP5-E2: MAIN->MGMT" place-before=[/ip firewall filter find comment="TP5: log-only, Vorstufe zum deny-by-default"] } } on-error={ :log info "tp5e2: 08 MAIN->MGMT warf" }
|
||||
:do { :if ([:len [/ip firewall filter find comment="TP5-E2: HA->MGMT api"]] = 0) do={ /ip firewall filter add chain=forward action=accept src-address=10.40.20.105 out-interface=vlan99 protocol=tcp dst-port=8728 comment="TP5-E2: HA->MGMT api" place-before=[/ip firewall filter find comment="TP5: log-only, Vorstufe zum deny-by-default"] } } on-error={ :log info "tp5e2: 09 HA->MGMT warf" }
|
||||
:do { :if ([:len [/ip firewall filter find comment="TP5-E2: Nautobot->MGMT ssh"]] = 0) do={ /ip firewall filter add chain=forward action=accept src-address=10.40.20.30 out-interface=vlan99 protocol=tcp dst-port=22 comment="TP5-E2: Nautobot->MGMT ssh" place-before=[/ip firewall filter find comment="TP5: log-only, Vorstufe zum deny-by-default"] } } on-error={ :log info "tp5e2: 10 Nautobot->MGMT warf" }
|
||||
|
||||
# 7) Same-VLAN mDNS. vlan10 -> vlan10 udp/5353, erzeugt vom mDNS-Repeater auf
|
||||
# dem Core selbst (17 Zeilen). Erreicht die forward-Kette und wuerde von
|
||||
# einem blanken Drop getroffen -> Discovery INNERHALB von MAIN kaputt.
|
||||
:do { :if ([:len [/ip firewall filter find comment="TP5-E2: same-VLAN mDNS"]] = 0) do={ /ip firewall filter add chain=forward action=accept in-interface=vlan10 out-interface=vlan10 protocol=udp dst-port=5353 comment="TP5-E2: same-VLAN mDNS" place-before=[/ip firewall filter find comment="TP5: log-only, Vorstufe zum deny-by-default"] } } on-error={ :log info "tp5e2: 11 same-VLAN mDNS warf" }
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# BEWUSST NICHT AUFGENOMMEN:
|
||||
#
|
||||
# vlan10 -> vlan30 (237x udp/3722) und vlan30 -> vlan10 (2x): das ist das
|
||||
# iPhone 10.40.30.201, das im IOT-SSID haengt. D2 ist entschieden — es wird
|
||||
# ins MAIN-SSID umgehaengt (Hands-on bei Christoph), dann verschwindet die
|
||||
# Richtung von selbst. Eine Whitelist auf .30.201 waere ausserdem instabil:
|
||||
# iOS vergibt pro SSID eine eigene Private Address.
|
||||
# => Vor Etappe 3 pruefen, ob die Zeilen aus dem Log verschwunden sind.
|
||||
#
|
||||
# MAIN -> IOT ICMP (lanscan.app, D3): keine Dauerregel. Gehoert in die
|
||||
# JIT-Admin-Gruppe (address-list mit timeout), Etappe 4.
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# Zaehlzeile: 11 Whitelist-Regeln erwartet. Per get_log zeilengenau auslesen —
|
||||
# der Deploy-Job zeigt den Geraete-Output nicht (Lehre aus Etappe 1).
|
||||
:log info ("tp5e2: ENDE whitelist-regeln=" . [:tostr [:len [/ip firewall filter find comment~"TP5-E2:"]]] . " logregel-disabled=" . [:tostr [/ip firewall filter get [find comment="TP5: log-only, Vorstufe zum deny-by-default"] disabled]])
|
||||
Reference in New Issue
Block a user