fix(PROJ-63): Defense-in-Depth Tenant-Scope-Härtung der Admin-Endpunkte

tenantAccessAllowed()-Check in allen {id}-Handlern von tenant_handlers.go,
tenant_domain_handlers.go und tenant_logo_handlers.go ergänzt — No-op für
globale Admins, zweite Verteidigungslinie für hypothetische tenant-gebundene
Admin-Sessions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
sysops
2026-06-30 14:37:39 +02:00
co-authored by Claude Sonnet 4.6
parent c1338f6721
commit dcb88317ac
6 changed files with 88 additions and 2 deletions
+30 -1
View File
@@ -20,7 +20,9 @@ Du entwickelst **archivmail** ein selbst gehostetes, unternehmenstaugliches
**Go-Modul: `archivmail`** — Imports sind immer `archivmail/internal/...`, NIEMALS `github.com/archivmail/...`
**Feature-Tracking:** Alle Features in `features/INDEX.md`. Feature-IDs: PROJ-X. Nächste verfügbare ID: PROJ-44.
**Feature-Tracking:** Alle Features in `features/INDEX.md`. Feature-IDs: PROJ-X. Die nächste
verfügbare ID steht live am Ende von `features/INDEX.md` — dort nachsehen, nicht aus dem
Gedächtnis annehmen (die Datei wird laufend fortgeschrieben).
## Deine Kernprinzipien
@@ -152,6 +154,33 @@ const (
- **Audit:** Jeder Zugriff (Suche, Export, Lesen) wird geloggt unveränderbar
- **Integrität:** SHA-256 im Dateinamen + DB für spätere Verifikation
### Architekturprinzip: Symmetrische Tenant-Scope-Checks (Lehre aus PROJ-61)
Jede neue per-ID-adressierbare Ressource (nicht nur Mails — auch Logos, Anhänge, Exporte,
Saved Searches, API-Keys, künftige Ressourcentypen) bekommt beim Entwurf **von Anfang an**
ein einheitliches Zugriffsmuster über alle CRUD-Pfade:
- Rollen-Check (`requireRole`) UND Tenant-Scope-Check (`tenantAccessAllowed()`) sind zwei
unabhängige Dimensionen — beide müssen auf JEDEM Pfad (GET, POST, DELETE) geprüft werden.
- Bei "global admin sieht alles, domain_admin nur eigenen Tenant"-Ressourcen: Lese- und
Schreibpfad MÜSSEN denselben Scope-Check verwenden. PROJ-61 entstand, weil der Lesepfad
einer Ressource (Tenant-Logo) nur `s.auth` hatte, während Schreib-/Löschpfad korrekt
`requireRole` + Tenant-Scope kombinierten — das Auseinanderlaufen von Geschwister-Endpunkten
ist das eigentliche Risiko, nicht ein einzelner fehlender Check.
- Beim Architektur-Entwurf eines neuen Ressourcentyps: definiere den Scope-Check EINMAL als
gemeinsame Hilfsfunktion, die alle Handler (GET/POST/DELETE) aufrufen — nie pro Handler neu
ausformulieren.
### Architekturprinzip: Neue Hintergrund-Jobs defaulten auf Batch, nicht Dauerbetrieb
Seit PROJ-56/58 ist die etablierte Linie: rechenintensive oder schreiblastige Hintergrund-
Verarbeitung (Indexierung, OCR, künftige ähnliche Jobs) soll beim Entwurf eine
`batch_mode`-Option vorsehen (Cron-getrieben, Default ggf. weiter Dauerbetrieb für
Abwärtskompatibilität), statt implizit als permanente Goroutine ohne Abschaltmöglichkeit zu
laufen. Performance-Budget (<200 MB RAM) gilt besonders für neue Worker-Pools — vor dem
Hinzufügen eines weiteren Dauerbetrieb-Workers prüfen, ob ein bestehender Worker den Job
mitübernehmen kann.
## Deine Arbeitsweise
### Bei Architektur-Anfragen:
+9
View File
@@ -89,6 +89,15 @@ ssh root@192.168.1.131 'manticore_backup --config /etc/manticoresearch/manticore
ssh root@192.168.1.131 'archivmail reindex --config /etc/archivmail/config.yml'
```
## GoBD-Hinweis
Der Manticore-Index ist **abgeleitete Suchdarstellung**, nicht die rechtlich maßgebliche
Quelle (Source of Truth = verschlüsselte Roh-Mails in `/var/archivmail/store/` + PostgreSQL-
Metadaten). Einträge aus dem Index löschen/ändern ist erlaubt (Reindex jederzeit möglich),
aber NIEMALS als Ersatz für eine echte GoBD-konforme Mail-Löschung verwenden — eine Mail aus
dem Index zu entfernen macht sie nicht rechtlich gelöscht, sie bleibt unverändert im Store.
Echte Löschungen laufen ausschließlich über `archivmail purge` (Retention + Markierung).
## Security
- Port 9306 NUR auf localhost: `listen = 127.0.0.1:9306:mysql`