Files
archivmail/docs/GOBD_DSGVO_CHECKLIST.md
T
sysops 6d67a6bbe7 docs: GoBD-Checklist auf aktuellen Stand bringen, Spec für PROJ-56c nachtragen
Checklist war seit 2026-06-13 nicht aktualisiert: PROJ-48/49/50/51/52 waren
laengst deployt, standen aber noch als fehlend/teilweise drin. PROJ-56c
(Cron-Purge mit Markierungspflicht) war im Code implementiert, hatte aber
nie eine eigene Feature-Spec — nachtraeglich dokumentiert.
2026-07-04 12:12:08 +02:00

61 lines
9.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# GoBD/DSGVO-Compliance-Checkliste archivmail
Bewertung gegen den "Leitfaden zur E-Mail-Archivierung in Deutschland" (VOI-Grundsätze, GoBD, DSGVO).
Stand: 2026-07-04, basierend auf Code-Review (nicht nur Spec-Review).
## Zusammenfassung
**Gut abgedeckt:** Verschlüsselung at-rest (AES-256-GCM) mit Pflicht-Warnung (PROJ-49), Volltextsuche
(Manticore), unveränderliches Audit-Log per DB-Trigger + append-only JSON-Lines (PROJ-48),
Retention/Löschsperre inkl. Dokumentenart-Kategorien (PROJ-34, PROJ-51), DSGVO-Löschersuchen-Workflow
mit GoBD-Vorrang (PROJ-50), Vollständigkeits-Reconciliation (PROJ-52), Multi-Tenant-Rollenmodell,
Integritätsprüfung per SHA-256 (PROJ-18), Export in EML/MBOX/ZIP/CSV (PROJ-12, PROJ-15, PROJ-39, PROJ-47).
**Verbleibende Lücken (priorisiert):**
1. **Migrationssicherheit teilweise** kein dokumentierter Compliance-Erhalt-Check nach Schema-/
Index-Migrationen (Punkt 10).
2. **Physische Tenant-Trennung fehlt** Storage ist logisch (DB) getrennt, nicht auf Dateisystem-
Ebene (Punkt 15, bekannt seit Tenant-Isolation-Review).
3. **Zeitstempel/Signaturerhalt (BSI TR 03125)** nicht implementiert (Nice-to-have, niedrige
Priorität, nur relevant bei signierten Mails im Kundenkreis).
4. **Informationspflicht der Mitarbeiter** organisatorisch, nicht im Code lösbar (Punkt 13).
---
## Checkliste
| # | Anforderung | Status | Begründung / Codeverweis | Empfehlung |
|---|---|---|---|---|
| 1 | **Vollständigkeit** 100% Ein-/Ausgang archiviert | ✅ Erfüllt | SMTP-BCC-Journal (PROJ-4), IMAP/POP3-Import (PROJ-3/14), EML/MBOX-Import (PROJ-2). SMTP-Daemon (`internal/smtpd/smtpd.go`) gibt bei Storage-Fehler `452` zurück → MTA-Retry, kein Verlust beim Empfang. Vollständigkeits-Reconciliation (PROJ-52, deployt 2026-07-04): täglicher Cron-Report `internal/reconciliation/` zählt archivierte Mails je Quelle, Alert bei >50% Abweichung vom 7-Tage-Schnitt, Audit-Eintrag `reconciliation_anomaly`. | |
| 2 | **Frühzeitigkeit** Archivierung bei Eingang/Ausgang | ✅ Erfüllt | SMTP-BCC-Journaling (PROJ-4) archiviert synchron beim Empfang/Versand; IMAP-Cron-Sync (PROJ-8) ergänzt. `internal/storage/storage.go:343 Save()` läuft direkt im Empfangspfad. | |
| 3 | **Unveränderbarkeit / Formaterhalt** | ✅ Erfüllt | `Save()` speichert Original-RFC2822-Bytes (ggf. gzip-komprimiert, PROJ-36) ohne inhaltliche Konvertierung; `Load()`/`maybeDecompress()` liefert Original zurück. Export liefert EML 1:1 (PROJ-12, `internal/api/export.go`). Kein Schreibzugriff/UPDATE auf gespeicherte Mail-Dateien im Code gefunden. | |
| 4 | **Zugriffsschutz** | ✅ Erfüllt | JWT-Auth (httpOnly Cookie), bcrypt Cost 12 (PROJ-1). Rollenmodell `user`/`auditor`/`admin` strikt getrennt; `admin` hat explizit KEINEN Mail-Zugriff. Tenant-Isolation via `tenantAccessAllowed()` (`internal/api/import_handlers.go:22`). | |
| 5 | **Wiederauffindbarkeit / Volltextsuche** | ✅ Erfüllt | Manticore-RT-Index (PROJ-30), Volltextsuche inkl. Anhänge via OCR (PROJ-35/44), Filter nach Datum/Absender/etc. (PROJ-6). | |
| 6 | **Aufbewahrungsfristen (konfigurierbar je Dokumentenart, i.d.R. 610 Jahre)** | ✅ Erfüllt | PROJ-51 (deployt 2026-06-13): Tabelle `archiving_rules` (`internal/storage/retention_rules.go`) — Muster-Regeln (Absender/Betreff/etc.) mit individueller `retention_days` pro Dokumentenart, Priorität bei mehreren Treffern, `retain_until_source` dokumentiert welche Regel griff. `Store.minRetentionDays`/`SetMinRetentionDays` erzwingt konfigurierbares Minimum. Admin-UI unter `/api/admin/archiving-rules`. | |
| 7 | **Löschsperre** | ✅ Erfüllt | PROJ-34 implementiert: `emails.retain_until`, `ErrRetentionLock` (`internal/storage/storage.go:27,659-667`), `Delete()` verweigert Löschung vor Fristablauf. Zusätzlich Cron-Purge (PROJ-56c, `cmd/archivmail/cmd_purge.go`, nachts 03:40 via `/etc/cron.d/archivmail`): löscht NUR Mails die BEIDE Bedingungen erfüllen — `retain_until < NOW()` UND vom Nutzer explizit `marked_for_deletion=TRUE` gesetzt (`ListExpiredMarkedMailIDs`, `internal/storage/mark_deletion.go:127-148`). Reiner Fristablauf ohne manuelle Markierung löscht nichts automatisch (Vier-Augen-Prinzip: Frist + Mensch). Der manuelle Admin-Button (`Store.Purge()`, `POST /api/admin/purge`) löscht dagegen alles abgelaufene ohne Markierungspflicht — bewusst getrennte, absichtlich unterschiedliche Semantik für Cron vs. manuelle Aktion. | |
| 8 | **Protokollierung/Audit-Log unveränderlich** | ✅ Erfüllt | PROJ-48 (deployt 2026-06-13): `internal/audit/audit.go` installiert Funktion `audit_log_no_mutation()` + Trigger `audit_log_immutable` (blockt UPDATE/DELETE auf DB-Ebene, idempotent via `CREATE OR REPLACE`/`DROP TRIGGER IF EXISTS`). Zusätzlich append-only JSON-Lines-Datei (`ResolvedLogPath()`, Default `/var/log/archivmail/audit.log`), Schreibfehler blockieren den DB-Pfad nicht (best effort, DB bleibt Quelle der Wahrheit). | |
| 9 | **Nachprüfbarkeit durch Dritte / GDPdU-Export** | ✅ Erfüllt | Export-Funktionen: Einzel-EML/PDF, ZIP-Massenexport mit `manifest.csv` (PROJ-12, `internal/api/export.go`), eDiscovery-ZIP mit `metadata.csv` + README (PROJ-39, `internal/api/ediscovery.go`), CLI-Export inkl. Tenant-Voll-Export (PROJ-15, PROJ-47, `cmd/archivmail/cmd_export.go`), Audit-Log-CSV-Export für Auditoren. | Optional: PROJ-47 (In Review) fertigstellen/QA. |
| 10 | **Migrationssicherheit** | ⚠️ Teilweise | Migrationstools vorhanden (PROJ-19 Mailpiler-Import, PROJ-30 Xapian→Manticore), `initSchema`/idempotente `ALTER TABLE ... ADD COLUMN IF NOT EXISTS` Pattern durchgängig genutzt (z.B. `storage.go:99-100`). Kein dokumentierter "Compliance-Erhalt-Check" nach Migration (z.B. automatischer Verify-Lauf nach Schema-Änderung). | Migrations-Runbook + Post-Migration-Integritätscheck (kann PROJ-18-Job nach Migration triggern) dokumentieren. |
| 11 | **Maschinelle Auswertbarkeit (Standardformate)** | ✅ Erfüllt | Export als EML (Original-MIME, PROJ-12/15), MBOX (`cmd_export.go`), CSV-Metadaten (PROJ-39). | |
| 12 | **Zeitstempel/Signaturerhalt (BSI TR 03125)** | ❌ Fehlt | Keine S/MIME- oder PGP-Signaturprüfung, kein qualifizierter Zeitstempel-Dienst im Code gefunden. Für die meisten KMU nicht zwingend erforderlich. | Als Backlog-Item vermerken, nur bei Bedarf (signierte Mails im Kundenkreis) als neue Spec aufnehmen. |
| 13 | **Informationspflicht der Mitarbeiter** | ❌ Fehlt (organisatorisch) | Nicht im Code prüfbar/lösbar. | Organisatorische Maßnahme: Betriebsvereinbarung / Datenschutzhinweis außerhalb des Systems. |
| 14 | **Trennung/Kennzeichnung personenbezogener Daten, Löschkonflikt Art. 5/17/32** | ✅ Erfüllt | PROJ-50 (deployt 2026-06-13): `internal/storage/dsgvo_requests.go` — Tabelle `dsgvo_requests`, Workflow sucht betroffene Mails (From/To/CC, Volltext via Manticore `AnyAddress`), löscht NUR Mails ohne aktive Löschsperre (`store.Delete` respektiert `retain_until`), lehnt den Rest mit Begründung "Aufbewahrungspflicht hat Vorrang" ab und protokolliert (`EventDSGVORequest`). Bekannte Deviation: `bcc_addr` ist im Schema vorhanden, aber `mailparser` befüllt BCC nicht (kein BCC-Header in archivierten Mails) — Such-Vollständigkeitszusage entsprechend einschränken. | Deviation (BCC) in Kunden-Doku erwähnen, sonst keine Aktion nötig. |
| 15 | **Mandantentrennung/Zugriffskontrolle nach Rolle (Multi-Tenant)** | ✅ Erfüllt | PROJ-21 Multi-Tenancy, `tenantAccessAllowed()` als Standardmuster (`internal/api/import_handlers.go:22`), Tenant-Quotas (PROJ-29), Pro-Tenant-Retention (`tenants.retention_days`). Laut Memory: keine physische Storage-Trennung pro Tenant (logische Trennung über `email_refs`/DB). | Bekannte Lücke (siehe Memory `project_tenant_isolation_review.md`): physische Storage-Trennung als optionales Härtungsfeature evaluieren, falls von Kunden gefordert. |
| 16 | **Verschlüsselung at-rest** | ✅ Erfüllt | PROJ-49 (deployt 2026-06-13): AES-256-GCM (`internal/storage/storage.go`, `encrypt()`), inkl. gzip vor Verschlüsselung (PROJ-36). `Store.EncryptionEnabled()` + `warnEncryptionStatus()` gibt beim Start eine WARN-Zeile aus wenn Keyfile fehlt/unlesbar/falsche Größe; `archivmail status` prüft `checkEncryption`; Dashboard (`handleSystemStats`) zeigt `encryption.enabled` systemweit. `Keyfile` bleibt technisch optional (Abwärtskompatibilität bestehender Installationen), aber Zustand ist jetzt sichtbar statt stillschweigend. | |
---
## Nächste Schritte (Vorschlag, Priorität absteigend)
1. **Migrations-Runbook** (Punkt 10): Compliance-Erhalt-Check nach Schema-/Index-Migrationen
dokumentieren (kann PROJ-18-Integritätsjob nach Migration triggern).
2. **Physische Tenant-Trennung** (Punkt 15) evaluieren, falls von Kunden gefordert
(siehe Memory `project_tenant_isolation_review.md`).
3. Nice-to-have: BSI TR 03125 Zeitstempel/Signaturerhalt (Punkt 12), nur bei konkretem Bedarf.
4. Organisatorisch: Mitarbeiter-Informationspflicht (Punkt 13) außerhalb des Codes klären.
**Erledigt seit Stand 2026-06-13:** PROJ-48 (Audit-Log-Unveränderbarkeit), PROJ-49
(Verschlüsselungspflicht/Warnung), PROJ-50 (DSGVO-Löschersuchen), PROJ-51 (Retention-Kategorien),
PROJ-52 (Vollständigkeits-Reconciliation), PROJ-47 (Tenant-Voll-Export, jetzt Deployed).