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.
61 lines
9.1 KiB
Markdown
61 lines
9.1 KiB
Markdown
# 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. 6–10 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).
|