feat(PROJ-65): Physische Tenant-Trennung im Storage-Layer (Hardlink-Ordner)

Jeder Tenant bekommt ein eigenes Verzeichnis store/tenant_<id>/, das per
Hardlink auf die kanonische content-adressierte Datei zeigt — das bestehende
Cross-Tenant-Dedup-Modell (email_refs M:N, PROJ-32/37) bleibt dadurch
erhalten, kein Speicherplatz-Mehrverbrauch. Neues CLI-Subcommand
`archivmail migrate-tenant-dirs` zieht Bestandsdaten einmalig nach
(idempotent). Zusätzlich neuer Status-Check checkStoragePermissions
(warnt bei zu offenen store_path-Rechten, analog checkEncryption/PROJ-49).

DB-gestützte Zugriffskontrolle bleibt der maßgebliche Zugriffspfad im Code;
die Tenant-Ordner sind eine zusätzliche Defense-in-Depth-Ebene für manuelle
Dateisystem-Audits. Kein lokaler go build möglich, QA folgt auf Testserver.
This commit is contained in:
sysops
2026-07-04 13:03:52 +02:00
parent cc30440e99
commit a15fa37619
8 changed files with 493 additions and 8 deletions
+6 -7
View File
@@ -8,16 +8,15 @@ Stand: 2026-07-04, basierend auf Code-Review (nicht nur Spec-Review).
**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).
mit GoBD-Vorrang (PROJ-50), Vollständigkeits-Reconciliation (PROJ-52), physische Tenant-Trennung im
Storage-Layer (PROJ-65), 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. **Physische Tenant-Trennung fehlt** Storage ist logisch (DB) getrennt, nicht auf Dateisystem-
Ebene (Punkt 15, bekannt seit Tenant-Isolation-Review).
2. **Zeitstempel/Signaturerhalt (BSI TR 03125)** nicht implementiert (Nice-to-have, niedrige
1. **Zeitstempel/Signaturerhalt (BSI TR 03125)** nicht implementiert (Nice-to-have, niedrige
Priorität, nur relevant bei signierten Mails im Kundenkreis).
3. **Informationspflicht der Mitarbeiter** organisatorisch, nicht im Code lösbar (Punkt 13).
2. **Informationspflicht der Mitarbeiter** organisatorisch, nicht im Code lösbar (Punkt 13).
---
@@ -39,7 +38,7 @@ Integritätsprüfung per SHA-256 (PROJ-18), Export in EML/MBOX/ZIP/CSV (PROJ-12,
| 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. |
| 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`). PROJ-65 (2026-07-04): zusätzlich physische Tenant-Trennung im Storage-Layer — Hardlink-Verzeichnisse `store/tenant_<id>/` (`internal/storage/tenant_dirs.go`), Dedup-Modell bleibt erhalten (keine Speicherplatz-Verdopplung), Backfill für Bestandsdaten (`archivmail migrate-tenant-dirs`). Storage-Verzeichnis-Permissions (0700) werden zusätzlich per `archivmail status` überwacht (`checkStoragePermissions`). DB-gestützte Zugriffskontrolle bleibt der maßgebliche Zugriffspfad im Code — die Tenant-Ordner sind eine zusätzliche Defense-in-Depth-Ebene für manuelle Dateisystem-Audits. | |
| 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. | |
---