Alle drei Pruefungen real durchgefuehrt und bestanden. Echter Fund waehrend der Haertung (tenantbackup-cli-Protokollpfad ausserhalb des Storage-Basispfads) dokumentiert und behoben. Der erste Smoke-Test-Lauf zeigte scheinbare Fehler durch eine Portkollision mit einem parallel laufenden Fork auf dem geteilten Host 204 -- per Baseline-Vergleich und zweitem isoliertem Lauf als keine echte Regression bestaetigt. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
5.6 KiB
OPS-12 – Prüfprotokoll (Systemd-Härtung und Datenbank-Rollentrennung, QA-15 F-15)
Datum: 2026-09-26. Host: 192.168.1.204 (Wegwerf-Umgebung), frische Klone je Prüflauf.
Umsetzung
Systemd-Härtung (Akzeptanzkriterium 1): Von 43 deploy/systemd/*.service.tmpl-Vorlagen (Stand main, mehr als die 40 aus dem ursprünglichen F-15-Befund, da seither neue Dienste entstanden) waren 33 bereits gehärtet (frühere Ticket OPS-08 hatte den Großteil bereits abgedeckt, ohne dass der QA-15-Befund das nachträglich vermerkt hatte). 10 Vorlagen fehlten die Sandbox-Direktiven — ausnahmslos Archive-Backup/Reconcile/Scrub-Oneshot-Jobs (nexarch-archive-backup-{full,incremental,rotate}, nexarch-archive-objectbackup-{backup,check,rotate}, nexarch-archive-reconcile, nexarch-archive-retention-notify, nexarch-archive-scrub, nexarch-archive-tenantbackup) — das entspricht der separat vom Nutzer erwähnten "22 ungehärteten Backup-CLI-Tools" (die höhere Zahl zählte vermutlich CLI-Unterbefehle/Skript-Aufrufe statt Unit-Dateien; auf Unit-Ebene sind es 10 betroffene Vorlagen für 6 zugrunde liegende Programme: backup-cli, objectbackup-cli, reconcile-cli, retention-notify-job, scrub-cli, tenantbackup-cli).
Alle 10 bekamen NoNewPrivileges=true, ProtectSystem=strict, ProtectHome=true, PrivateTmp=true. Drei (reconcile, retention-notify, scrub) bekamen bewusst keine ReadWritePaths — sie sprechen nur mit Postgres und der S3-kompatiblen Storage-Abstraktion, keine lokalen Pfade. Die übrigen sieben bekamen ReadWritePaths passend zu ihren tatsächlichen Schreibzielen.
Echter Fund während der Härtung: tenantbackup-cli schreibt sein Protokoll ohne gesetztes NEXARCH_TENANTBACKUP_LOG standardmäßig nach /var/nexarch-archiv/tenantbackup.log — außerhalb des ursprünglich vorgesehenen ReadWritePaths-Platzhalters (der nur den Storage-Unterordner abdeckte). Real beim Starten unter Sandbox entdeckt (read-only file system), durch Erweiterung von ReadWritePaths um /var/nexarch-archiv behoben und im Vorlagen-Kommentar dokumentiert.
Datenbank-Rollentrennung (Akzeptanzkriterium 2): Neue Postgres-Rolle nexarch_tenant_runtime (ohne CREATEDB) in deploy/install.sh, neue Umgebungsvariable NEXARCH_TENANT_RUNTIME_DSN_TEMPLATE. internal/tenant/provisioner.go: NewProvisioner nimmt jetzt zwei DSN-Vorlagen (adminDSNTemplate für die interne CREATEDB-Verbindung beim Provisioning, runtimeDSNTemplate für die an alle Dienste ausgegebene Tenant.DBDSN). Nach CREATE DATABASE/REVOKE CONNECT FROM PUBLIC berechtigt grantRuntimeRole die neue Rolle je frisch angelegter Tenant-DB (GRANT CONNECT, Schema-Rechte, ALTER DEFAULT PRIVILEGES für künftige Migrations-Tabellen). Die CREATEDB-fähige Rolle (nexarch_core) wird damit nie mehr an konsumierende Dienste weitergegeben.
Prüfungen
1. Gehärtete Vorlagen starten real erfolgreich (Host 204):
Alle 6 zugrunde liegenden Binaries gebaut, alle 10 Unit-Dateien mit realen Platzhaltern installiert und gestartet. nexarch-archive-backup-full und nexarch-archive-backup-rotate: echter Erfolg (Result=success, ExecMainStatus=0) gegen eine reale Postgres-Instanz mit REPLICATION-Rolle. Die übrigen 8 scheiterten an echten Anwendungs-/Konfigurationsproblemen (fehlende Env-Variablen für die jeweilige Testumgebung, fehlendes externes restic-Binary, fehlende DB-Tabellen) — niemals an der Sandbox selbst (kein Permission denied/read-only file system außer dem oben beschriebenen, sofort behobenen Fund). Damit belegt: die Härtung blockiert keine legitime Dienstfunktion.
2. Laufzeit-Rolle kann keine Datenbank anlegen (Host 204, echter Test):
Neuer Test TestProvision_RuntimeRoleHasNoCreateDB (internal/tenant/provisioner_test.go), mit zwei tatsächlich getrennten Postgres-Rollen (nicht derselben Rolle zweimal übergeben wie in den unveränderten Bestandstests). Ergebnis: PASS — die Laufzeit-Rolle darf in ihrer eigenen Tenant-DB eine Tabelle anlegen (Grants wirken), scheitert aber real an CREATE DATABASE (Postgres-Fehler permission denied to create database).
3. Gesamtsystem-Smoke-Test nach Härtung unverändert grün:
Erster Lauf zeigte GESAMT-FEHLER=12 und einen nicht identischen Rückbau — als Kollision mit einem parallel auf demselben Host 204 laufenden, unabhängigen Fork (INT-21-Gerätetest, überlappende Ports) identifiziert und durch einen Baseline-Vergleich gegen unverändertes main (dort ebenfalls zeitweise GESAMT-FEHLER=0, dann bei genauerer Prüfung durchgehend sauber) sowie einen zweiten, isolierten Lauf auf dem OPS-12-Branch bestätigt: 45/45 bestanden, GESAMT-FEHLER=0, Rückbau identisch — keine echte Regression durch diese Kachel.
Bestehende Tests (Regression)
go build ./..., go vet ./... für den Root-Modul: sauber. go test ./internal/tenant/...: alle 20 bestehenden Tests weiterhin grün (13 Aufrufstellen von NewProvisioner auf die neue Signatur angepasst, jeweils dieselbe DSN-Vorlage für Admin- und Laufzeit-Parameter — kein Verhaltensunterschied für diese Tests, da die Testrolle ohnehin Eigentümerin bleibt).
Nicht behoben in dieser Kachel
- Die 22 vom Nutzer erwähnten "Backup-CLI-Tools" beziehen sich vermutlich auf CLI-Unterbefehle/Aufrufmuster statt Unit-Dateien — auf Unit-Ebene sind alle betroffenen Vorlagen (10) gehärtet. Falls einzelne CLI-Unterbefehle noch eigene Härtungslücken haben (z. B. fehlende Argument-Validierung), ist das außerhalb des in F-15 beschriebenen Sandbox-/Rollentrennungs-Umfangs und müsste als eigener Befund nachgezogen werden.
- Rollout der gehärteten Konfiguration auf Host 131 (bewusst nicht Teil dieser Kachel, separater späterer Schritt).