diff --git a/README.md b/README.md index d723fa9..d5e4cf2 100644 --- a/README.md +++ b/README.md @@ -13,9 +13,10 @@ Selbst gehostete DDI-Lösung (DNS, DHCP, IP-Adressverwaltung) im Stil von VitalQ | M2 Config-Generator (BIND/Kea aus dem Datenmodell, geprüft mit echtem BIND 9.18/9.20 und Kea 2.6/3.2) | abgeschlossen (`v0.3.0`) | | M3 Agent verwaltet (Registrierung, mTLS, signierte Revisionen, Anwenden mit Prüfung/Health-Check/Rollback, Leases; End-to-End-Test mit BIND und Kea) | abgeschlossen (`v0.4.0`) | | M4 Pull und Push (Betriebsmodi, „Jetzt ausrollen“, offene Änderungen, Diff, Rollback, Live-Status) | abgeschlossen (`v0.5.0`) | -| M5–M6 | geplant, siehe [ARCHITECTURE.md](docs/ARCHITECTURE.md#11-meilensteine) | +| M5 Cluster und Zonen (DNS-Primary/Secondary mit TSIG, Kea-HA, Zonen und Records, dynamische Zonen, Lease-Übernahme) | abgeschlossen (`v0.6.0`) | +| M6 Auslieferung (Installer für Debian/Ubuntu/EL9, gehärtete systemd-Units, Pakete, Release-Signatur, Messungen, Betriebs- und Sicherheitsdoku) | abgeschlossen (`v0.7.0`) | -Der Management-Server verwaltet Netze und Adressen (QIP-artige Tabelle), Benutzer, Lizenz und Audit-Log. Aus den Daten erzeugt er die BIND- und Kea-Konfiguration als unveränderliche Revisionen (**Ausrollen**). Die Agents (`ddi-agent-dns`, `ddi-agent-dhcp`) registrieren sich mit einem Einmal-Token, holen die signierten Revisionen über mTLS, prüfen und aktivieren sie, rollen bei Fehlern zurück und melden Zustand und Leases (**Agents**, **Leases**). +Installation: [docs/INSTALL.md](docs/INSTALL.md). Der Management-Server verwaltet Netze und Adressen (QIP-artige Tabelle), Zonen und Records, DNS- und DHCP-Cluster, Benutzer, Lizenz und Audit-Log. Aus den Daten erzeugt er die BIND- und Kea-Konfiguration als unveränderliche Revisionen (**Ausrollen**). Die Agents (`ddi-agent-dns`, `ddi-agent-dhcp`) registrieren sich mit einem Einmal-Token, holen die signierten Revisionen über mTLS, prüfen und aktivieren sie, rollen bei Fehlern zurück und melden Zustand und Leases (**Agents**, **Leases**). ## Dokumentation diff --git a/docs/LOGBUCH.md b/docs/LOGBUCH.md index 35a1bc0..128e4db 100644 --- a/docs/LOGBUCH.md +++ b/docs/LOGBUCH.md @@ -6,7 +6,7 @@ Neue Einträge oben im Abschnitt „Verlauf“ ergänzen und den Abschnitt „St --- -## Stand (2026-10-14, nach M5) +## Stand (2026-10-16, nach M6) | Meilenstein | Status | Tag | | --- | --- | --- | @@ -16,32 +16,37 @@ Neue Einträge oben im Abschnitt „Verlauf“ ergänzen und den Abschnitt „St | M3 Agent verwaltet | fertig, CI grün | `v0.4.0` | | M4 Pull und Push | fertig, CI grün | `v0.5.0` | | M5 Cluster und Zonen | fertig, CI grün | `v0.6.0` | -| M6 Auslieferung | **als Nächstes** | – | +| M6 Auslieferung | fertig, CI grün | `v0.7.0` | +| M7 (Standalone, DHCPv6, DNSSEC, Discovery) | nur Schnittstellen vorbereitet (Brief §12) | – | -Branch `main`, alles gepusht nach `https://git.beugsiud.de/beug.k/DDI`. Release `v0.1.0` mit Artefakten auf Gitea veröffentlicht; `v0.2.0` ebenso über den Release-Workflow. +Branch `main`, alles gepusht nach `https://git.beugsiud.de/beug.k/DDI`. Releases mit Artefakten über den Release-Workflow. -### Nächster Schritt: M6 (Auslieferung) +### Nächster Schritt: Abnahme auf echten Maschinen (Brief §14) -Laut Brief: `install.sh`, Release-Build, optional Pakete, `SYSTEM-REQUIREMENTS.md` mit Messungen, `OPERATIONS.md`, `SECURITY.md`, Härtung, End-to-End-Test der Installation in sauberen VMs/Containern (Debian, Ubuntu, Rocky). Der Installer muss dabei einrichten, was bisher nur Entwicklungsumgebung und End-to-End-Test vorgeben: `named.conf` mit `ddi-suite-keys.conf` vor `ddi-suite.conf` und dem Optionen-Include, Zonenverzeichnis unter `/var/lib/bind` (schreibbar für `named`, inkl. `secondary/`), Kea-Pfade (Konfiguration, Socket-Verzeichnis 0750, Lease-Datei, HA-Benutzer- und Passwortdatei lesbar für den Kea-Benutzer), Generator-Einstellungen passend zur Agent-Konfiguration (Punkte 9–10 unten). +M0–M6 sind umgesetzt. Was die CI nicht abdecken kann, steht noch aus: + +1. **Release-Signatur einrichten** (nur du): Schlüsselpaar erzeugen, Secret `RELEASE_SIGNING_KEY` in Gitea setzen und den öffentlichen Schlüssel in `scripts/install.sh` (`RELEASE_PUBLIC_KEY_PEM`) eintragen – Anleitung in [RELEASE.md](RELEASE.md). Bis dahin prüft der Installer nur `SHA256SUMS` und warnt. +2. **Abnahme nach Brief §14** auf drei VMs (Debian 12 Server, je eine VM für DNS- und DHCP-Agent): Installation nach [INSTALL.md](INSTALL.md), echter Keygen-Lizenzschlüssel (Punkt 1 unten), Oberfläche im Browser durchklicken (Punkt 2), DHCP mit echtem Client (Lease → Adresstabelle → `manual_dhcp`), Lizenz sperren/Keygen unerreichbar (Lesemodus nach Karenzzeit, DNS/DHCP laufen weiter). +3. Danach bewusst entscheiden, welche offenen Punkte vor einem `v1.0.0` nötig sind (z. B. HA mit TLS, Kea-DDNS, Neuverschlüsselung beim Master-Key-Wechsel). ### Offene Punkte -1. **Keygen live geprüft (2026-10-13), aber noch nicht mit dem Go-Code selbst.** Mit einem zweiten, eigens dafür bereitgestellten Schlüssel (nur in der Umgebung, nirgends gespeichert) die exakte Aufruffolge des `KeygenProvider` nachgespielt und jede Antwort wie `verify()` geprüft: alle signiert, Digest und Signatur gültig. Ablauf: `validate-key` → `NO_MACHINES`, Aktivierung → 201, erneut → 422 `FINGERPRINT_TAKEN` (Erfolg), Validierung → `VALID`, Entitlements → `DDI_Networks`, Heartbeat → 200, Deaktivierung → 204. Lizenz-Metadaten leer, also keine Grenzen. **Offen:** der Go-Code selbst gegen die echte Instanz – per Umgebungsvariable aktivierter Live-Test in der CI (Schlüssel als Gitea-Secret) oder beim ersten echten Betrieb prüfen. `tools/keygen-setup/keygen-setup.sh` ist nie gegen die Instanz gelaufen. -2. **Oberfläche nie im echten Browser bedient**, inzwischen mit vielen neuen Dialogen (Cluster, Zonen, Records, TSIG). Abgesichert durch Vitest-Komponententests und den Smoke-Test des Release-Binaries. Beim ersten Durchklicken (`make dev-up`, `make dev-admin`, `make run-server`, `cd web && npm run dev`) auf Layout-Fehler und Abläufe achten. -3. **Frontend-Bundle:** Seiten werden seit M5 per `React.lazy` nachgeladen; der Hauptteil ist noch 481 KB (154 KB gzip), vor allem Bibliotheken und beide Sprachdateien. Weiter verkleinern: Vendor-Split, Sprachdateien nachladen. -4. **Service-Schicht ohne eigene Abdeckungszahl:** wird über die API-Tests geprüft; Nachweis mit `go test -coverpkg=./server/... ./server/internal/httpapi`. -5. **GitHub-Rate-Limit in der CI:** `setup-go`/`setup-node` holen Manifeste von GitHub (60 Anfragen/Stunde je IP). Bisher nur Warnungen. Falls Jobs scheitern: Go/Node in `scripts/ci/install-tools.sh` selbst mit Prüfsumme installieren. -6. **TanStack Table 9 und React Router 8** sind erschienen; bewusst auf Table 8 / Router 7 geblieben. Upgrade später als eigener Schritt. -7. **Kea-HA:** nur mit Kea ≥ 3.0 (geprüft mit 3.2.1); Benutzer und Passwort liegen in Dateien, weil Kea 3 Klartext-Anmeldedaten ablehnt. Die HA-Verbindung läuft per HTTP mit Basic-Auth, **ohne TLS** (folgt später; Zertifikate könnte die Agent-CA ausstellen). Beide Peers melden dieselben Leases; die doppelte Übernahme in die Adresstabelle ist harmlos. -8. **SOA-Seriennummer bei lokalem Rollback:** Rollbacks über das UI erzeugen eine neue, höhere Revision. Rollt der Agent auf dem Primary lokal zurück, sinkt die Seriennummer dort; Secondaries behalten bis zur nächsten Revision die höhere (ADR 0023). -9. **Zertifikatserneuerung mit verlorener Antwort:** Erhält der Agent die neue Antwort nicht, gilt beim Server schon die neue Seriennummer; der Agent muss neu registriert werden. In `OPERATIONS.md` (M6) beschreiben. -10. **Kea `config-reload` liest die Datei, mit der Kea gestartet wurde.** Weicht `dhcp.config_file` des Agents davon ab, meldet der Reload Erfolg mit alter Konfiguration; nur der Dateivergleich im Health-Check fällt auf. Installer (M6) muss Pfade, Hook-Verzeichnis (Kea 3.x: einkompiliert) und Socket-Verzeichnis (Modus 0750) passend setzen. -11. **Server-Tests mit Zeitbezug:** Agent-Kern- und Agent-API-Tests nutzen kurze Intervalle (50 ms bis 15 s). Bei sporadischen CI-Fehlern dort zuerst an Timing denken. -12. **Nicht umgesetzt aus dem Brief (optional bzw. später):** DNS-Namen dynamischer Leases per Kea-DDNS (`kea-dhcp-ddns`) in eine dynamische Zone schreiben (§5.2, „optional pro Netz“); GSS-TSIG für Active Directory (in `docs/ACTIVE-DIRECTORY.md` als nicht unterstützt beschrieben); Bindung eines Enrollment-Tokens an einen Cluster (ADR 0008) – Mitglieder werden nach der Registrierung im UI zugeordnet. -13. **Cluster-Kleinigkeiten:** Wird ein Agent gelöscht, verlässt er seinen Cluster per Kaskade ohne eigenen Audit-Eintrag am Cluster. Eine noch nicht übertragene Secondary-Zone ist im Health-Check nur „eingeschränkt“; direkt nach dem Ausrollen kann der Secondary kurz `tsig indicates error` melden, wenn er den neuen Schlüssel vor dem Primary aktiviert hat (NOTIFY holt die Zonen danach, im End-to-End-Test beobachtet). -14. **Aus den Messungen (M6, `test/bench`):** CSV-Import war mit ~300 Zeilen/s zu langsam für eine Datei an der Grenze von 50.000 Zeilen (60-s-Timeout); behoben: Netze und vorhandene Einträge werden einmal geladen (~1.100 Zeilen/s, Lauf 95), Frist für den Import 10 min. `GET /addresses` ohne Netzfilter braucht bei 50.000 Einträgen 110–240 ms (Zählung, `ILIKE`-Suche, tiefe Offsets). Jede Revision speichert alle Dateien voll (50.000 Adressen: 4,6 MiB) – Aufbewahrung empfehlen bzw. später deduplizieren. -15. **Schlüsselrotation unvollständig:** Master-Key-Datei kann mehrere Schlüssel halten, aber es gibt kein Neuverschlüsseln vorhandener Werte; keine Rotation für Agent-CA, Bundle-Schlüssel und HA-Passwort (nur über Neuanlage des Clusters). Beschrieben in `OPERATIONS.md`/`SECURITY.md`. -16. **Master-Key-Rechte:** Der Server verweigert `master.key`, wenn Gruppe oder andere lesen dürfen (0400/0600 nötig); ADR 0024 nannte 0640 root:. Der Installer muss 0400 mit Eigentümer Dienstbenutzer setzen. +1. **Keygen live geprüft (2026-10-13), aber noch nicht mit dem Go-Code selbst.** Die Aufruffolge des `KeygenProvider` wurde per Skript mit echtem Schlüssel nachgespielt (alle Antworten signiert und gültig; `validate-key` → `NO_MACHINES`, Aktivierung 201, erneut 422 `FINGERPRINT_TAKEN`, Validierung `VALID`, Entitlements `DDI_Networks`, Heartbeat 200, Deaktivierung 204). **Offen:** der Go-Code selbst gegen die echte Instanz, z. B. bei der Abnahme mit `ddi-server license set-key` oder per Live-Test in der CI mit Gitea-Secret. `tools/keygen-setup/keygen-setup.sh` ist nie gegen die Instanz gelaufen. +2. **Oberfläche nie im echten Browser bedient** (inzwischen viele Dialoge: Cluster, Zonen, Records, TSIG). Abgesichert durch Vitest und Smoke-Tests. Bei der Abnahme auf Layout-Fehler und Abläufe achten. +3. **Frontend-Bundle:** Seiten werden nachgeladen; der Hauptteil ist noch 481 KB (154 KB gzip). Weiter verkleinern: Vendor-Split, Sprachdateien nachladen. +4. **Service-Schicht ohne eigene Abdeckungszahl:** Nachweis mit `go test -coverpkg=./server/... ./server/internal/httpapi`. +5. **GitHub-Rate-Limit in der CI:** `setup-go`/`setup-node` holen Manifeste von GitHub. Falls Jobs scheitern: Go/Node in `scripts/ci/install-tools.sh` selbst mit Prüfsumme installieren. +6. **TanStack Table 9 und React Router 8** sind erschienen; bewusst auf Table 8 / Router 7 geblieben. +7. **Kea-HA:** nur mit Kea ≥ 3.0; Zugangsdaten aus Dateien; HA-Verbindung per HTTP mit Basic-Auth **ohne TLS**. Beide Peers melden dieselben Leases (harmlos). +8. **SOA-Seriennummer bei lokalem Rollback:** Rollt der Agent auf dem Primary lokal zurück, sinkt die Seriennummer dort; Secondaries behalten bis zur nächsten Revision die höhere (ADR 0023). +9. **Kea `config-reload` liest die Datei, mit der Kea gestartet wurde.** Der Installer setzt die Pfade passend; wer Kea von Hand umkonfiguriert, siehe `OPERATIONS.md` §10.3. +10. **Server-Tests mit Zeitbezug:** Agent-Kern- und Agent-API-Tests nutzen kurze Intervalle. Bei sporadischen CI-Fehlern zuerst an Timing denken (so auch der AXFR-Integrationstest, behoben durch Start-Reihenfolge). +11. **Nicht umgesetzt aus dem Brief (optional bzw. später):** Kea-DDNS für Namen dynamischer Leases (§5.2, optional); GSS-TSIG; Bindung eines Enrollment-Tokens an einen Cluster (ADR 0008). +12. **Cluster-Kleinigkeiten:** Löschen eines Agents entfernt ihn ohne eigenen Audit-Eintrag aus seinem Cluster; Secondary kann direkt nach dem Ausrollen kurz `tsig indicates error` melden (NOTIFY holt die Zonen danach). +13. **Aus den Messungen:** `GET /addresses` ohne Netzfilter braucht bei 50.000 Einträgen 110–240 ms. Jede Revision speichert alle Dateien voll (50.000 Adressen: 4,6 MiB) – Aufbewahrung (`retention.revisions_keep`) empfehlen bzw. später deduplizieren. Nicht gemessen: Speicher der Agents, 50 verbundene Agents, viele gleichzeitige Benutzer, Kea mit HA. +14. **Schlüsselrotation unvollständig:** kein Neuverschlüsseln vorhandener Werte beim Master-Key-Wechsel; keine Rotation für Agent-CA, Bundle-Schlüssel und HA-Passwort (nur Neuanlage des Clusters). Beschrieben in `OPERATIONS.md`/`SECURITY.md`. +15. **Installer, nicht in der CI geprüft:** `--kea-source distro` (Hooks ohne Pfad), AppArmor/SELinux im erzwingenden Modus (Container setzen sie nicht durch), echte Downloads vom Gitea-Release (die CI nutzt `--from-dir`). EL9 braucht EPEL für Kea von ISC. +16. **Zertifikatserneuerung mit verlorener Antwort:** Agent muss neu registriert werden (`enroll --force`), beschrieben in `OPERATIONS.md` §8.2. --- @@ -122,6 +127,15 @@ Datenbanktests brauchen `DDI_TEST_DATABASE_URL` (z. B. `postgres://ddi:ddi-dev-o ## Verlauf +### 2026-10-16 – M6 Auslieferung (`v0.7.0`) + +- Verträge vorab: [ADR 0024](adr/0024-auslieferung-installer-m6.md), gehärtete Unit-Vorlagen `deploy/systemd/*.service.in`, `scripts/render-units.sh`. Vorher per Probe-Workflow auf einem Wegwerf-Branch geprüft, dass die CI-Runner privilegierte systemd-Container starten können (Debian, Ubuntu, Rocky) und Netz zu Paketquellen, Gitea und Keygen haben. Dann drei Agents (Installer, Release/Server, Messungen/Doku); alle brachen mehrfach am Sitzungslimit ab und liefen nach `SendMessage` weiter. Installer- und Mess-Agent durften für CI-Läufe je einen eigenen Remote-Branch pushen (`m6-installer`, `m6-bench`, danach gelöscht). +- **Installer** `scripts/install.sh`: Rollen `server`, `agent-dns`, `agent-dhcp` auf Debian 12/13, Ubuntu 22.04/24.04, EL9; Vorabprüfung nach `SYSTEM-REQUIREMENTS.md` §3; Prüfsummen und (sobald eingerichtet) Ed25519-Signatur; PostgreSQL mit Peer-Authentifizierung (kein DB-Passwort); Agents laufen als Benutzer ihres Dienstes (`bind`/`named`, `_kea`/`kea`), ohne root; Kea 3.2 aus dem ISC-Repository (EL9 braucht EPEL); markierte Blöcke in `named.conf`, kollidierende Distributionsoptionen umkehrbar auskommentiert; idempotent, `--upgrade`, `--uninstall [--purge]`, `--dry-run`, Aufräumen bei Abbruch. Neu `docs/INSTALL.md`. +- **Installationstest** (Workflow `install`, Lauf 101): je System ein privilegierter systemd-Container, alle Rollen installieren, Agents per Token registrieren, Revision ausrollen, `dig` und Kea-Reservierung prüfen, Hardening und Nicht-root-Prozesse prüfen, zweiter Lauf ohne Änderungen, Upgrade auf eine zweite Version, Deinstallation mit und ohne `--purge`. Auf allen fünf Systemen grün. +- **Release/Server:** `ddi-server license set-key` (stdin, Exit-Codes 0–4), Aufbewahrung (`retention.audit_days`, `retention.revisions_keep`, täglich, nie benutzte Revisionen), `.deb`/`.rpm` mit nfpm, Signatur `SHA256SUMS.sig` im Release-Workflow (Secret `RELEASE_SIGNING_KEY`, Anleitung `docs/RELEASE.md`), Namensprüfung `scripts/check-brand.sh` (ADR 0018). +- **Von den Tests gefunden:** ISC-Kea vergleicht den Socket-Pfad wörtlich mit dem einkompilierten `/var/run/kea` (Lösung: `KEA_CONTROL_SOCKET_DIR=/run/kea` per Drop-in); `kea-dhcp4 -t` braucht Netlink in der Agent-Unit; Rocky-`named.conf` beschränkt `listen-on`/`allow-query` auf localhost; der Server lehnt einen gruppenlesbaren Master-Key ab (ADR korrigiert: 0400); der CSV-Import war mit ~300 Zeilen/s zu langsam für die 50.000-Zeilen-Grenze (jetzt ~1.100/s); der AXFR-Integrationstest war wackelig (Secondary startete vor dem Primary). +- **CI-Lehren:** Ein Runner hatte für das Standard-Build-Netz von Docker kein ausgehendes Netz – Images mit `--network host` bauen. Die CI-Runner haben nur ~1,9 GB freien Platz; der Installationstest prüft deshalb erst, dass die Vorabprüfung abbricht, und nutzt dann `--force`. + ### 2026-10-15 – M6 Messungen, Betriebs- und Sicherheitsdoku - Benchmark `test/bench/` (`make bench`, Workflow `bench`, nur `workflow_dispatch`): Server mit PostgreSQL 17, synthetische Daten (5.000 und 50.000 Einträge) per CSV-Import über die API; BIND 9.20 mit `dnsperf` und Kea 3.2.1 mit `perfdhcp` auf den Dateien aus `GET /config/preview`. Ergebnisse (Lauf 93, Runner 4 vCPU Skylake, 7,7 GiB) in `SYSTEM-REQUIREMENTS.md`; neu `OPERATIONS.md`, `SECURITY.md`.