docs(PROJ-66): Backup & Restore Runbook schreiben

docs/BACKUP_RESTORE_RUNBOOK.md deckt beide Sicherungsebenen ab: App-eigenes
CLI-Backup (archivmail backup/restore, PROJ-66) und Infrastruktur-Ebene
(PBS + Sync auf Zweitserver, pct restore). Enthaelt Bitwarden-Keyfile-
Escrow-Anleitung, Pflicht-Verifikationsschritte (reconcile/reindex/
Stichprobe), Rotation-vs-DSGVO-Hinweis und den offenen Punkt "noch kein
Restore-Test durchgefuehrt" als groesste verbleibende Luecke.

AC 8 aus PROJ-66 damit erfuellt; AC 6 (Restore-Test) und AC 7 (Alerting)
bleiben offen.
This commit is contained in:
sysops
2026-07-05 21:11:39 +02:00
parent e19f2e5b6e
commit 4eba165250
2 changed files with 244 additions and 1 deletions
+170
View File
@@ -0,0 +1,170 @@
# Backup & Restore Runbook archivmail
Bezug: `features/PROJ-66-backup-strategie.md` (Spec + Entscheidungsverlauf),
`docs/GOBD_DSGVO_CHECKLIST.md` Punkt 7 (Löschsperre) und 15 (Mandantentrennung).
Ziel: belegen können, dass ein Totalausfall von Store, Keyfile oder
PostgreSQL nicht zu unwiederbringlichem Mail-Verlust führt — und dass ein
Restore im Ernstfall tatsächlich funktioniert, nicht nur theoretisch existiert.
Gilt für: `archivmail backup`/`archivmail restore` (PROJ-66, App-eigenes
CLI-Backup) und ergänzend die Proxmox Backup Server (PBS) + Sync-auf-
Zweitserver-Sicherung auf Infrastruktur-Ebene.
## Grundsatz
Store, Keyfile und PostgreSQL-Metadaten sind **nur gemeinsam** nutzbar:
- Store ohne DB: Dateien vorhanden, aber keine Zuordnung zu Mail/Tenant.
- Keyfile ohne Store: irrelevant, nichts zu entschlüsseln.
- DB ohne Keyfile: Metadaten da, Mail-Inhalte nicht mehr lesbar (GoBD-Verstoß).
Ein Backup, das nur eine dieser drei Komponenten sichert, ist wertlos. Ein
Backup, das nie zurückgespielt wurde, ist nicht verifiziert — siehe
"Regelmäßiger Restore-Test" unten.
## Zwei unabhängige Sicherungsebenen
1. **Infrastruktur-Ebene (PBS + Sync auf Zweitserver)** — läuft vom
Proxmox-Host aus, sichert den kompletten Container (Store+Keyfile+
Config+PostgreSQL-Datendir+Audit-Log in einem Snapshot). Von innerhalb
des Containers nicht sichtbar/steuerbar. Siehe Memory
`project_backup_infra_pbs` für CLI-Befehle (`vzdump`, `pct restore`).
2. **App-eigenes Backup (`archivmail backup`/`restore`)** — ergänzt Ebene 1
um einen anwendungskonsistenten `pg_dump` (statt reinem Crash-Consistency-
Snapshot) und einen selektiven, von PBS unabhängigen Restore-Weg.
Keine der beiden Ebenen ersetzt die andere. Ein vollständiger Restore-Test
sollte mindestens einmal **beide** Wege durchlaufen haben (siehe unten).
## Backup erstellen
```bash
archivmail backup --config /etc/archivmail/config.yml --dest <ziel> --keep 14
```
- `<ziel>` MUSS auf einem vom Produktivsystem physisch getrennten Ziel
liegen (zweiter Host, NAS, o.ä.) — siehe PROJ-66-Spec, Abschnitt
"Backup-Ziel: On-Site vs. Off-Site". Ein Backup auf derselben Platte
schützt nicht vor Hardware-Ausfall.
- Schreibt `<ziel>/<timestamp>/`: `postgres.dump` (`pg_dump -Fc`), `store/`
(Hardlink-erhaltende Kopie, PROJ-65-Tenant-Ordner bleiben ohne
Speicherplatz-Verdopplung erhalten), `keyfile`, `config.yml`, `audit.log`
(best-effort).
- `--keep N` behält die letzten N Backup-Verzeichnisse, löscht ältere —
**nur nach erfolgreichem Lauf**. Ein fehlgeschlagener Lauf lässt den
partiellen Ordner stehen und rotiert nichts weg (Diagnose-Möglichkeit,
kein Verlust eines guten alten Backups).
- Cron-Aktivierung: `deploy/cron.d/archivmail` enthält eine auskommentierte
Beispielzeile. Erst aktivieren, wenn ein konkretes `--dest`-Ziel feststeht.
## Keyfile-Escrow (Bitwarden)
Zusätzlich zum Backup: das Keyfile als unabhängige Kopie in Bitwarden
hinterlegen (Secure Note, eigene Collection mit eingeschränktem Zugriff —
das Keyfile entschlüsselt das **gesamte Archiv aller Mandanten**).
```bash
cat /etc/archivmail/keyfile
# → Wert 1:1 in eine neue Bitwarden Secure Note kopieren, Metadaten
# ergänzen (Server/Installation, Datum, wer hinterlegt hat).
```
Zweck: unabhängiger Wiederherstellungsweg, falls PBS/Snapshot-Infrastruktur
selbst nicht verfügbar ist. Ersetzt nicht das App-Backup — beide parallel
pflegen. Bei künftiger Keyfile-Rotation (aktuell nicht vorgesehen) den
Bitwarden-Eintrag im selben Schritt aktualisieren.
## Restore durchführen
**Vorbereitung:**
1. Zielsystem: frischer Server/Container oder vorhandenes System im
Wartungsmodus. `archivmail`/`archivmail-web` müssen gestoppt sein —
`archivmail restore` stoppt/startet die Dienste NICHT selbst.
2. Backup-Verzeichnis identifizieren: `<ziel>/<timestamp>/`.
**Durchführung:**
```bash
systemctl stop archivmail archivmail-web
archivmail restore --config /etc/archivmail/config.yml \
--source <ziel>/<timestamp> [--force]
```
- Ohne `--force`: bricht ab, wenn `store_path`/Keyfile bereits Inhalt haben
— Schutz gegen versehentliches Überschreiben eines laufenden Systems.
`--force` nur auf einem bewusst freigeräumten/frischen Zielsystem nutzen.
- `--skip-db`: überspringt `pg_restore`, falls die Datenbank bereits separat
wiederhergestellt wurde (z.B. via PBS-Snapshot der DB-Ebene).
- Stellt Store (Hardlinks erhalten), Keyfile, Config und PostgreSQL
(`pg_restore --clean --if-exists`) wieder her. Gibt am Ende die
Pflicht-Verifikationsschritte aus (siehe unten).
**Verifikation (Pflicht, nicht optional):**
```bash
systemctl start archivmail archivmail-web
# Health-Check wie im Standard-Deploy-Workflow (Backend ✓, Frontend ✓)
archivmail reconcile --days 7 # PROJ-52: Zählvergleich Store vs. DB muss aufgehen
archivmail reindex # Manticore aus Store+DB neu aufbauen
# Stichprobe: 3-5 zufällige Mails über die UI öffnen und lesbar entschlüsseln
# lassen — beweist, dass Keyfile+Store+DB zueinander passen.
```
Restore-Ergebnis (Mail-Zahl, Zeitstempel, Dauer, welche Verifikationsschritte
liefen) dokumentieren — Prinzip "Zählen, Prüfen, Belegen" wie im
Migrations-Runbook.
## Restore aus einem PBS-Snapshot (Infrastruktur-Ebene)
Auf dem Proxmox-**Host** (nicht im Container):
```bash
pct restore <neue-id> <pbs-storage>:backup/ct/<quell-id>/<timestamp> --storage <ziel-storage>
```
Restored als neuer Container mit `<neue-id>` — der Quell-Container bleibt
unangetastet. Danach dieselbe Verifikation wie oben (`reconcile`, `reindex`,
Stichprobe) im neuen Container durchführen. PostgreSQL kam dabei aus einem
Crash-Consistency-Snapshot, nicht aus einem `pg_dump` — WAL-Replay beim
Start ist der Normalfall, sollte aber beim Test explizit beobachtet werden
(`journalctl -u postgresql` auf Recovery-Meldungen prüfen).
## Regelmäßiger Restore-Test
Ein Backup, das nie zurückgespielt wurde, ist nicht verifiziert. Empfehlung:
mindestens vierteljährlich einen vollständigen Restore auf einen isolierten
Test-Container durchführen (**nicht auf 131/132!**) — einmal über
`archivmail restore` (App-Backup) und mindestens einmal über `pct restore`
(PBS-Snapshot), jeweils mit vollständiger Verifikation. Bislang (Stand
2026-07-05) wurde noch kein Restore-Test durchgeführt — das ist die
kritischste offene Lücke in der Backup-Strategie, nicht das Fehlen eines
Backup-Ziels.
## Rotation vs. DSGVO-Löschung
Backup-Rotation (`--keep N`, bzw. PBS-Retention) ist unabhängig von der
GoBD-Aufbewahrungsfrist der Mails selbst (PROJ-51). Eine in Produktion
bereits DSGVO-gelöschte Mail (PROJ-50) kann in einem älteren Backup noch
enthalten sein. Rotation muss kurz genug sein, dass gelöschte Daten nach
spätestens N Zyklen auch aus Backups verschwinden — Zeitraum mit
Datenschutzbeauftragtem/Nutzer abstimmen, kein rein technisches Thema.
## Monitoring / Alerting (noch offen)
Größtes Risiko bei Cron-Backups: der Job schlägt still fehl, niemand merkt
es bis zum Ernstfall (Lehre aus PROJ-58: Cron-Zeilen fehlten wochenlang
trotz aktivem Code). Aktuell **nicht gebaut**: ein sichtbarer Alarm, wenn
das letzte erfolgreiche Backup älter als ein Schwellenwert ist. Bis dahin:
Log-Datei des Backup-Cron-Jobs (`/var/log/archivmail/backup.log`, sobald der
Cron aktiviert ist) manuell im Rahmen der regulären Betriebs-Checks prüfen.
## Verweis
- `features/PROJ-66-backup-strategie.md` — vollständige Spec, Optionsabwägung,
QA-Ergebnisse.
- `docs/MIGRATION_RUNBOOK.md` — Vorbild für den "Zählen, Prüfen, Belegen"-Stil.
- Memory `project_backup_infra_pbs` — PBS/Sync-Infrastruktur-Details,
`vzdump`/`pct restore`-Befehle.
- Memory `project_132_teilproduktiv` — 132 ist kein reiner Testserver,
Backup-Sorgfalt gilt dort genauso wie auf 131.