Files
archivmail/features/PROJ-11-audit-log.md
T
sysops 7c29ee88bd docs: vollständige README, PROJ-2 Web-Upload, PROJ-19 Mailpiler-Migration
README.md:
- Vollständige Dokumentation aller implementierten Funktionen
- Konfigurationsreferenz, Installation, Systemd, REST-API-Übersicht
- In-Progress-Features klar gekennzeichnet

PROJ-2 (EML/MBOX Web-Upload):
- POST /api/admin/upload – Multipart-Upload mit Hintergrund-Job
- GET /api/admin/upload/{jobID}/progress – Polling
- Admin-Tab "Import" mit Drag-and-Drop, Fortschrittsbalken, Abschlussbericht

PROJ-19 (Mailpiler Migration):
- archivmail import-piler mit Methoden: pilerexport | direct | auto
- Direct: AES-256-CBC + zlib mit defensiven Fallbacks
- pilerexport: Wrapper um mailpilers Export-Tool

Status-Updates: PROJ-3, PROJ-4, PROJ-6, PROJ-7, PROJ-10, PROJ-11 → Deployed

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 09:23:34 +01:00

146 lines
6.0 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.
# PROJ-11: Audit-Log & Compliance-Berichte
## Status: Deployed
**Created:** 2026-03-12
**Last Updated:** 2026-03-13
## Dependencies
- Requires: PROJ-1 (Authentifizierung) Audit-Einträge sind an Nutzer geknüpft
## User Stories
- Als Admin möchte ich sicherheitsrelevante Ereignisse im Audit-Log einsehen, damit ich Zugriffe und Änderungen nachvollziehen kann.
- Als Admin möchte ich den Audit-Log nach Datum, Nutzer und Ereignistyp filtern.
- Als Admin möchte ich den Audit-Log als CSV exportieren, damit ich ihn für externe Prüfungen verwenden kann.
## Erfasste Ereignisse
**Ja wird geloggt:**
- Login (Erfolg und Fehlschlag) inkl. IP-Adresse
- Logout
- Suchanfragen (Suchbegriff, Anzahl Treffer, Nutzer)
- Import gestartet / abgeschlossen / fehlgeschlagen (Quelle, Anzahl E-Mails)
- Export gestartet / abgeschlossen (Format, Anzahl E-Mails)
**Nein wird nicht geloggt:**
- Lesezugriff auf einzelne E-Mails (kein per-Mail-Leselogging)
## Acceptance Criteria
- [ ] Jeder Log-Eintrag enthält: Zeitstempel (UTC), Nutzer-ID, Ereignistyp, Details (z.B. Suchbegriff, Import-Quelle), IP-Adresse
- [ ] Audit-Log-Ansicht **nur für Auditoren** unter `/audit/` kein Zugriff für `admin` oder `user`
- [ ] Filterung nach: Datum (vonbis), Nutzer, Ereignistyp
- [ ] Paginierung (50 Einträge pro Seite)
- [ ] Export als CSV (gefilterte oder vollständige Ansicht, Streaming-Download)
- [ ] Einträge sind unveränderlich: kein UPDATE/DELETE durch Admin oder Anwendung möglich
- [ ] Retention konfigurierbar in `config.yml` (`audit.retention_days`), kein Standardwert erzwungen
- [ ] Doppelte Speicherung: PostgreSQL (für GUI-Abfragen) + Append-only Logdatei auf Disk (als unveränderliches Backup)
- [ ] Logdatei-Format: JSON Lines (ein Eintrag pro Zeile)
## Edge Cases
- Audit-Log über Jahre sehr groß → paginierte DB-Abfragen mit Index auf `(timestamp, event_type, user_id)`, kein Full-Table-Scan
- Nutzer DSGVO-gelöscht → Audit-Einträge behalten, `user_id` durch `"anonymized"` ersetzen, IP-Adresse löschen
- Logdatei nicht beschreibbar beim Start → Warnung loggen, Dienst läuft weiter (DB-Log bleibt aktiv)
- Gleichzeitige Schreibzugriffe auf Logdatei → Append mit file lock
## Technical Requirements
- PostgreSQL: separate Tabelle `audit_log`, kein DELETE/UPDATE per DB-Constraint (Row-Level Security oder Trigger)
- Logdatei: `/var/log/archivmail/audit.log` (Pfad konfigurierbar), append-only, JSON Lines
- Log-Rotation über `logrotate` (extern konfiguriert), Datei wird nie vom Dienst selbst rotiert oder gelöscht
- Zeitstempel immer UTC (RFC 3339)
---
## Tech Design (Solution Architect)
### Komponentenstruktur
**Next.js Frontend (`/audit/*`):**
```
/audit ← nur für Auditoren (RoleGuard)
└── AuditTable
├── Spalten: Zeitstempel, Nutzer, Ereignis, Details, IP
├── Filter-Leiste
│ ├── Datepicker: von bis
│ ├── Dropdown: Nutzer auswählen
│ └── Dropdown: Ereignistyp
├── Paginierung (50 pro Seite)
└── [CSV exportieren] Button → Streaming-Download
```
**Go Backend:**
```
Audit-Service (intern, kein eigener HTTP-Handler)
├── WriteEvent(event AuditEvent)
│ ├── → INSERT INTO audit_log (kein UPDATE/DELETE je möglich)
│ └── → Append zu /var/log/archivmail/audit.log (JSON Line)
│ └── File-Lock beim Schreiben (sync.Mutex)
└── Audit-API (nur für Auditoren)
├── GET /api/audit/events ← Paginiert, gefiltert
└── GET /api/audit/export ← Streaming-CSV-Download
```
### Datenmodell
**Tabelle `audit_log`** (append-only via DB-Trigger):
| Feld | Beschreibung |
|------|-------------|
| `id` | Sequentielle ID |
| `timestamp` | UTC, RFC 3339 |
| `user_id` | Nutzer-ID (NULL nach DSGVO-Löschung) |
| `user_email` | E-Mail zum Zeitpunkt des Events (für Lesbarkeit nach Anonymisierung) |
| `event_type` | `login_ok`, `login_fail`, `logout`, `search`, `import_start`, `import_done`, `import_fail`, `export_start`, `export_done` |
| `details` | JSON: Suchbegriff / Import-Quelle / Anzahl / etc. |
| `ip_address` | IPv4/IPv6 (NULL nach DSGVO-Löschung) |
**DB-Constraint:** PostgreSQL-Trigger verhindert `UPDATE` und `DELETE` auf der gesamten Tabelle → physische Unveränderlichkeit.
**Logdatei-Format** (`/var/log/archivmail/audit.log`, JSON Lines):
```
{"ts":"2024-03-01T10:00:00Z","user":"alice@firma.de","event":"search","details":{"q":"Rechnung","hits":42},"ip":"192.168.1.1"}
```
### Schreibfluss
```
Beliebige Aktion (Login, Suche, Import...)
audit.WriteEvent() aufgerufen
├── PostgreSQL INSERT (non-blocking, Goroutine)
└── File-Append mit sync.Mutex
(Datei nicht beschreibbar? → Warnung auf stderr, Dienst läuft weiter)
```
### DSGVO-Löschfluss (Nutzer anonymisieren)
```
DELETE /api/admin/users/{id}
├── audit_log: user_id → NULL, ip_address → NULL
│ user_email → "anonymized"
└── Logdatei: bleibt unverändert (tamper-evident)
```
### Technische Entscheidungen
| Entscheidung | Begründung |
|---|---|
| **Audit-Ansicht nur für Auditoren** | Strict role separation — Admin hat keine Einsicht in Zugriffsprotokolle |
| **DB-Trigger für Unveränderlichkeit** | Applikationscode kann versehentlich löschen — Trigger ist eine härtere Garantie |
| **Doppelte Speicherung** | DB für GUI-Abfragen; Logdatei als tamper-evident Backup für externe Prüfungen |
| **logrotate extern** | Dienst rotiert nie selbst — Logdatei bleibt unter Systemadmin-Kontrolle |
| **DSGVO: IP-Adresse löschen, Event behalten** | Personenbezug entfernen, Compliance-Nachweis bleibt erhalten |
| **Composite Index `(timestamp, event_type, user_id)`** | Schnelle gefilterte Abfragen auch bei sehr großem Log über Jahre |
### Abhängigkeiten
**Go Backend:** Nur Stdlib + pgx (bereits vorhanden).
**Next.js:** shadcn/ui Table, Select, DatePicker (bereits installiert).
## QA Test Results
_To be added by /qa_
## Deployment
_To be added by /deploy_