Files
bf-infra/docs/handoff-20260831-tp16.3-paragraph2-3-durch.md
Christoph Emsenhuber 6f6fa71ffa TP38 bestaetigt + Uebergabeprompt fuer TP16.3 §5 (CNAME-Flip)
- TP38 (OOB-Mgmt, untagged-VLAN99-Port je Switch): Nummer von Christoph
  bestaetigt, Herkunft des Nummernwechsels im TP-Abschnitt vermerkt.
- Neu: docs/tp16.3-paragraph5-session-handoff-prompt.md -- fertiger
  Prompt fuer die Flip-Session, nach der Konvention der drei bereits
  vorhandenen *-session-handoff-prompt.md.
  Enthaelt als erste Auflage die offene Drift-Entscheidung (128/135),
  die vor dem ersten Flip fallen muss.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-31 16:24:18 +02:00

7.6 KiB
Raw Blame History

Handoff — TP16.3 §2/§3 durch: drei Connectoren live, eine Entscheidung offen

2026-08-31, Vor-Ort-Session. Nachfolger von handoff-20260831-tp16.3-vorort-session.md. Nicht Teil dieser Session: §5 (CNAME-Flip) und §6 (Abbau).


1. Was jetzt steht

bf-public ist healthy mit 12 Connectoren (3 APs × 4 CF-Edges) — der Tunnel hatte vorher null. Je ein cloudflared 2026.6.1 läuft auf ap1, ap2 und ap3.

ap1 ap2 ap3
container-Paket 7.24.1 ✅ 7.24.1 ✅ 7.24.1 ✅
device-mode container yes ✅ yes ✅ yes ✅
Container R running R running R running
.tar gelöscht ✅ ✅ ✅
Flash frei 54,0 MiB 54,6 MiB 55,0 MiB

WLAN auf allen drei zurück, CAPs state=Ok am Manager. Backups je AP liegen auf dem Gerät (vor-tp16.3-apN.backup) und lokal unter ~/tp16.3/backups/ — inklusive vollständigem /export (nicht der MCP-Export, s. Punkt 4).


2. 🔴 Die eine offene Entscheidung: Compliance steht auf 128/135

Nach vollem Refresh (Backup → Intended → Compliance, nicht die stale Zahl von vorher):

Gerät Regel Inhalt
ap1 / ap2 / ap3 ip-address /ip address add address=172.17.0.1/24 interface=veth-cf
ap1 / ap2 / ap3 ip-firewall-nat masquerade, Kommentar TP31: cloudflared egress
crs326-core wifi-security ft-over-ds — die bekannte, unverändert

Ursache ist ein Widerspruch zwischen zwei Dokumenten, kein Ausrutscher: Runbook §3.4 schreibt Direkt-Writes für veth/ip address/nat vor, die Governance stellt /ip address und /ip firewall unter GC-Pflicht. Ich bin dem Runbook gefolgt.

Die sechs Drifts sind inhaltlich richtig — die Config soll dort stehen, ohne sie läuft kein Container. Der saubere Weg ist, sie ins Soll zu heben (AP-Template bzw. ConfigContext ap-common), damit die Compliance sie als konform sieht. 🔴 Kein Re-Baseline (macht die Drift-Erkennung wertlos) und kein Rückbau (killt die Tunnel). ⚠️ /interface veth erzeugt keine Drift — dafür existiert keine ComplianceRule. Wenn das Soll angepasst wird, gehört die Frage dazu, ob veth überhaupt erfasst sein soll.


3. 🔴 Drei Runbook-Fehler, die diese Session aufgedeckt hat

(a) Die Flash-Rechnung war um Faktor 2,5 zu optimistisch. §3.5 rechnete mit „28 MB .tar

  • ~28 MB entpackt ≈ 39 MB Rest". Die 28 MB sind die komprimierte Archivgrösse; entpackt misst cloudflare/cloudflared:2026.6.1 72.926.208 B = 69,5 MiB. Der Import braucht Tar und entpacktes Abbild gleichzeitig ⇒ 95,7 MiB gegen ~90 MiB frei. Das offizielle Image passt auf keinen der drei APs. ⚠️ docker image inspect .Size führt in die Irre (meldete 27.463.950). Für Flash-Budgets docker export | wc -c messen.

Lösung, ausgerollt: eigenes FROM scratch-Image aus dem — nachweislich statisch gelinkten — Binary (36,8 MB) plus CA-Bundle: 35,3 MiB, Spitzenbedarf 70,6 MiB. Build-Skript liegt jetzt im Repo (tools/build-cfd-image.py), ein Neubau ist byte-identisch (f818bf40…). 🔑 Der Pin ist die Binary-SHA256 e93824f6…, und cloudflared bestätigt sie beim Start selbst (Version 2026.6.1 (Checksum e93824f6…)) — im Log aller drei APs nachlesbar.

(b) docker save taugt seit Docker 25 nicht mehr als Quelle. Mit containerd-Image-Store schreibt es OCI-Layout (blobs/sha256/, gzip-Layer); RouterOS will docker-v1 und meldet no config found in manifest — klingt nach kaputtem Image, ist das Format. (Konverter für den Fall, dass man doch ein Docker-Image braucht: tools/oci2docker.py, prüft die Layer-Digests gegen rootfs.diff_ids.)

(c) /container/envs heisst auf ROS 7.24.1 list=, nicht name=. Mit name= kommt bad parameter name bzw. unknown parameter name. Auch MikroMCPs manage_container_env benutzt name= und ist damit für dieses Feld unbrauchbar.


4. Vier weitere Funde

  • 🔴 Der device-mode-Bestätigungs-Boot installiert KEINE Pakete. Auf ap1 lag die .npk schon bereit, als device-mode gesetzt wurde — der Stromzyklus hat container: yes bestätigt und die Datei verbraucht, ohne zu installieren. Reihenfolge ist Pflicht: erst Paket-Reboot, dann device-mode. (Nachholen ging per SSH, ohne zweiten Gang zum Gerät.)
  • 🟡 A - AVAILABLE in /system package print ist ein Download-Katalog, kein Paket auf dem Gerät. Gegenprobe: crs326-core hat 2,9 MB frei von 16 MB, listet aber wifi-qcom (10,1 MB) und rose-storage (4,3 MB) als „available"; die Grössen sind arch-spezifisch. enable löste einen Internet-Fetch aus — auf ap1/ap2 per device-mode=home gesperrt. Der .npk-Weg bleibt richtig.
  • 🟡 MikroMCPs export_config exportiert unvollständig: 301 Bytes gegen 6,2 KiB bei direktem /export. Ein Rollback-Artefakt, das existiert und trotzdem fast leer ist — dieselbe Klasse wie „Lücke statt Fehlermeldung". Für Backups /export file=… per SSH.
  • ⚠️ WLAN-Abnahme nur teilweise belegbar: main (3 Clients) und iot (27) haben frische Leases; media/untrusted/guest hatten schon vor dem Umbau null Clients. Kein Rückschritt, aber auch kein Beleg — nicht als „grün" buchen.

5. 🔴 Sicherheitsvorfall in dieser Session — Rotation nötig

Beim Suchen des Nautobot-Tokens hat eine unzureichende sed-Maskierung (grep -n … | sed 's/:.*TOKEN/…/' | cut -c1-60) zwei Werte im Klartext ins Transkript geschrieben:

  • NAUTOBOT_SUPERUSER_API_TOKEN
  • NAUTOBOT_GITEA_TOKEN

beide aus docs/nas-vlan20/stacks/210-nautobot.yml. Als verbrannt behandeln → TP30. Das ist exakt die Falle, die seit 2026-08-28 in der CLAUDE.md steht (der SHELLY_DEVICE_PW-Fall). Merkregel, die offenbar noch nicht scharf genug formuliert war: ein Maskierungs-Muster, das auf : ankert, matcht bei grep -n den Zeilennummer-Präfix statt den Wert. Sicher ist nur sed -E 's/(TOKEN|PASSWORD|SECRET|KEY|PASS)=.*/\1=<redacted>/' — auf den Schlüsselnamen ankern, nie auf ein Trennzeichen, das auch im Präfix vorkommt.


6. Repo-Zustand

  • Branch claude/nervous-williams-acf000 ist hier hereingemergt. Konflikte aufgelöst:
    • Nummernkonflikt TP37: main hatte TP37 = Nautobot als Netzwerkdoku (User-Okay 08-30), der Branch TP37 = OOB-Mgmt. Letzterer ist auf TP38 umnummeriert. ✅ Von Christoph bestätigt (2026-08-31).
    • Drei CF-Rollback-Snapshots hatten denselben Dateinamen bei verschiedenem Inhalt (bf-mm v4/6 Regeln vs. v6/2 Regeln, analog bf-nas, bf-pve) — zwei Zeitpunkte, beide „vor-tp16.3-schnitt" genannt. Keiner verworfen: der ältere liegt jetzt als *-vor-hostname-schnitt.json daneben.
  • Neu: tools/build-cfd-image.py, tools/oci2docker.py.
  • mcp/mikromcp/config/routers.yaml meldet weiter rosVersion: "7.24" für alle fünf (live 7.24.1) — kosmetisch, unangetastet gelassen.

7. Nächste Schritte

  1. Entscheidung zu Punkt 2 (sechs Drifts ins Soll heben) — vor dem Flip, sonst geht man mit erklärter, aber ungeklärter Drift in den Produktivpfad.
  2. §5 CNAME-Flip, einzeln mit Abnahme dazwischen, Testname zuerst (§5.1). ▸ Fertiger Übergabeprompt: tp16.3-paragraph5-session-handoff-prompt.md. 🔴 healthy beweist nur, dass der Connector mit Cloudflare redet — nicht, dass das Origin antwortet. Der Streckenbeweis bis Caddy ist §5.1.
  3. §6 Abbau frühestens 7 Tage nach dem Flip.
  4. TP30: die zwei Tokens aus Punkt 5 rotieren.