TenantAtlas/docs/audits/2026-03-09-enterprise-rbac-scope-audit.md
2026-03-09 11:39:36 +01:00

29 KiB

Enterprise RBAC, Scope Enforcement & Navigation Governance Audit

Datum: 9. März 2026 Anwendung: TenantPilot / TenantAtlas Stack: Laravel 12, Filament v5, Livewire v4, PostgreSQL, Tailwind v4 Auditor: Enterprise SaaS Security & Architecture Audit Scope: RBAC, Multi-Tenancy, Scope Enforcement, Navigation Governance, Filament Authorization


1. Executive Security / Structure Assessment

Gesamturteil: Teilweise robust — mit gezieltem Hardening-Bedarf

Die Anwendung verfügt über ein architektonisch durchdachtes, capability-first RBAC-Modell mit klarer Trennung von Platform/Workspace/Tenant-Scopes. Die Kernarchitektur (CapabilityResolver, UiEnforcement, Membership-Manager, Policies) ist solide und enterprise-geeignet.

Allerdings gibt es strukturelle Lücken in folgenden Bereichen:

  • System-Panel-Widgets aggregieren cross-workspace/cross-tenant Daten ohne Kompartimentierung
  • Einige Monitoring-Pages fehlen explizite canAccess() Checks und verlassen sich ausschließlich auf Middleware
  • AuditLog-Modell hat keine workspace_id Spalte und damit kein strukturelles Workspace-Scoping
  • Einige Modelle (OperationRun, BaselineProfile, AlertRule) haben keine Immutabilitäts-Traits am Model-Level
  • URL-basierte Enumeration von sequenziellen IDs ist möglich (Finding, OperationRun)

Die 5 kritischsten RBAC-/Scope-Probleme

# Problem Severity
1 System Panel leakt Cross-Workspace/Cross-Tenant Operational Data — ControlTower-Widgets zeigen Workspace-Namen, Tenant-Namen und Fehlerstatistiken aller Mandanten an jeden PlatformUser CRITICAL
2 Directory-Pages exponieren alle Tenants/Workspaces — System/Directory-Seiten erlauben Aufzählung aller registrierten Tenants/Workspaces mit Health-Status und Permission-Gaps HIGH
3 AuditLog hat kein strukturelles Workspace-Scoping — Nur tenant_id, kein workspace_id; Scoping ist rein auf Query-Level und kann bei neuen Zugangspfaden umgangen werden HIGH
4 Monitoring-Pages (Operations, AuditLog) fehlen canAccess() Checks — Verlassen sich nur auf Middleware + Query-Scoping, nicht auf explizite Page-Level Authorization MEDIUM
5 Sequenzielle IDs in URLs erlauben Enumeration — Finding-IDs, OperationRun-IDs sind sequential integers in Deep Links und Notifications MEDIUM

Die 5 wichtigsten Korrekturen

# Maßnahme Priorität
1 System-Panel Kompartimentierung: Capability-Granularisierung für cross-workspace Sicht P0
2 canAccess() auf allen Monitoring-Pages implementieren P1
3 AuditLog-Modell um workspace_id ergänzen mit Migration + Scoping-Trait P1
4 OperationRun + BaselineProfile + AuditLog mit DerivesWorkspaceId-Trait absichern P2
5 UUID-basierte Route-Keys für sensitive Ressourcen (Finding, OperationRun) evaluieren P2

2. Access Model Map

Subjekte

Subjekt Guard Scope Modell
Platform User platform System-weit PlatformUser
Workspace Owner web Workspace User + WorkspaceMembership(role=owner)
Workspace Manager web Workspace User + WorkspaceMembership(role=manager)
Workspace Operator web Workspace User + WorkspaceMembership(role=operator)
Workspace Readonly web Workspace User + WorkspaceMembership(role=readonly)
Tenant Owner web Tenant User + TenantMembership(role=owner)
Tenant Manager web Tenant User + TenantMembership(role=manager)
Tenant Operator web Tenant User + TenantMembership(role=operator)
Tenant Readonly web Tenant User + TenantMembership(role=readonly)

Scopes

Scope Kontext Enforcement
Platform System-Administration (break-glass, directory, ops) platform Guard + PlatformCapabilities
Workspace Organisation/Account-Isolation WorkspaceMembership + WorkspaceCapabilityResolver + WorkspaceContext (Session)
Tenant Mandant innerhalb eines Workspace TenantMembership + CapabilityResolver + Filament::getTenant()

Kernobjekte pro Scope

Scope Objekte
Platform PlatformUser, Access Logs, Break-Glass-Sessions
Workspace Workspace, WorkspaceMembership, WorkspaceSetting, AlertRule, AlertDestination, BaselineProfile, OperationRun (multi-tenant)
Tenant Tenant, TenantMembership, Policy, PolicyVersion, BackupSet, BackupItem, BackupSchedule, RestoreRun, Finding, ReviewPack, InventoryItem, EntraGroup, ProviderConnection, TenantPermission, TenantRoleMapping
Ambivalent AuditLog (nur tenant_id, kein workspace_id), OperationRun (hat workspace_id, aber kein Immutabilitäts-Trait), AlertDelivery (workspace_id + optional tenant_id)

Capability-Muster

Klar und konsistent:

  • Capability-first Design über Capabilities::* und PlatformCapabilities::*
  • Static Registry (Capabilities::all(), Capabilities::isKnown())
  • Rolle→Capability Mapping über RoleCapabilityMap und WorkspaceRoleCapabilityMap
  • Gates werden dynamisch aus Capabilities registriert (AuthServiceProvider)
  • UiEnforcement erzwingt dreilagige Autorisierung (Visibility → Disabled → Server Guard)

Inkonsistent:

  • Einige Policies nutzen Gate::allows(), andere nutzen CapabilityResolver::can() direkt
  • System-Panel nutzt separate PlatformCapabilities ohne Kompartimentierung innerhalb des System-Scopes
  • AuditLog hat keinen eigenen Capability-Check — Sichtbarkeit wird durch Page-Navigation gesteuert

3. Findings Table

ID Severity Kategorie Datei / Klasse Scope UI-Symptom Technische Ursache Risiko Empfohlene Korrektur
F-01 CRITICAL Cross-Scope Data Leak App\Filament\System\Widgets\ControlTowerTopOffenders System→All Widget zeigt Top-10-Fehler mit Workspace+Tenant-Namen Query ohne jegliche Scope-Filterung: OperationRun::query()->selectRaw('workspace_id, tenant_id...') Jeder PlatformUser sieht Betriebsdaten aller Mandanten Capability-basierte Kompartimentierung oder Anonymisierung im System-Panel
F-02 CRITICAL Cross-Scope Data Leak App\Filament\System\Widgets\ControlTowerKpis System→All KPI-Dashboard zeigt Gesamtstatistiken über alle Workspaces Globale OperationRun::query() ohne WHERE-Klausel Informations-Leaking über Betriebsumfang und Fehlerquoten Scope-Filter oder Capability-Granularisierung
F-03 CRITICAL Cross-Scope Data Leak App\Filament\System\Widgets\ControlTowerRecentFailures System→All Zeigt letzte fehlgeschlagene Runs mit Workspace-Namen Ungefilterter Query Sensitive Betriebs-Metadaten sichtbar Scope-aware oder anonymisiert
F-04 HIGH Tenant Enumeration App\Filament\System\Pages\Directory\Tenants System Directory listet alle Tenants mit Health, Status, Permission Gaps Tenant::query()->with('workspace') ohne Scope Reconnaissance: Angreifer sieht alle Mandanten, deren Konfigurationsprobleme und Provider-Status Capability-basierter Zugang oder Scope-Einschränkung
F-05 HIGH Workspace Enumeration App\Filament\System\Pages\Directory\Workspaces System Directory listet alle Workspaces mit Tenant-Count und Fehlerquoten Workspace::query() ohne Scope Reconnaissance: vollständige Sicht auf Struktur und Probleme aller Organisationen Wie F-04
F-06 HIGH Missing Structural Scope App\Models\AuditLog Tenant/Workspace AuditLog-Einträge haben kein workspace_id Model hat nur tenant_id, kein Workspace-Feld Bei neuen Zugangspfaden oder Queries ohne Tenant-Kontext könnten Audit-Daten cross-workspace leaken Migration: workspace_id Spalte + NOT NULL + DerivesWorkspaceIdFromTenant Trait
F-07 MEDIUM Missing canAccess() App\Filament\Pages\Monitoring\Operations Admin Seite ist über /admin/operations direkt erreichbar Kein expliziter canAccess() Check, nur Middleware+Query-Scoping Falls Middleware fehlschlägt oder umgangen wird, keine zweite Schutzschicht canAccess() mit WorkspaceCapabilityResolver implementieren
F-08 MEDIUM Missing canAccess() App\Filament\Pages\Monitoring\AuditLog Admin Seite über /admin/audit-log erreichbar, shouldRegisterNavigation=false Kein canAccess(), nur shouldRegisterNavigation=false und OperateHubShell Hidden page ohne Page-Level Auth ist per URL erreichbar canAccess() implementieren
F-09 MEDIUM URL Enumeration Notification Deep Links + Route {run} Tenant OperationRun-IDs in Notification-URLs sind sequential integers OperationRunLinks::tenantlessView($run) nutzt Integer-ID ID-Enumeration erlaubt Erkennung valider Run-IDs (Auth verhindert Lesezugriff) UUID-basierte Route-Keys oder Rate-Limiting
F-10 MEDIUM URL Enumeration Finding-URLs in Tenant Panel Tenant Finding-IDs in Links: /findings/140, /findings/139 Sequential integer keys in URLs Ähnlich wie F-09 UUID-basierte Anzeige
F-11 MEDIUM No Model Immutability App\Models\OperationRun Workspace/Tenant N/A Kein DerivesWorkspaceIdFromTenant Trait; workspace_id wird per boot() auto-filled, aber nicht immutabel erzwungen Theoretische Reassignment-Möglichkeit (kein aktueller Exploit-Pfad) DerivesWorkspaceIdFromTenant Trait hinzufügen
F-12 MEDIUM No Model Immutability App\Models\BaselineProfile Workspace N/A Kein Scoping-Trait; workspace_id muss bei Creation gesetzt werden Developer-Fehler bei zukünftigen Code-Änderungen möglich Trait oder DB-Constraint
F-13 LOW Break-Glass Scope App\Filament\System\Pages\RepairWorkspaceOwners System PlatformUser kann Owner für beliebigen Workspace zuweisen Nur USE_BREAK_GLASS Capability geprüft, keine Workspace-Zugehörigkeitsvalidierung Intentional (Emergency-Feature), aber unkompartimentiert Dokumentation und Audit-Alerting sicherstellen; optional: Require 4-eyes
F-14 LOW Access Log Exposure App\Filament\System\Pages\Security\AccessLogs System Zeigt alle Platform-Logins und Break-Glass-Aktivitäten Nur CONSOLE_VIEW Capability erforderlich Offenlegen, wer System-Zugang hat und wann Separate Capability SECURITY_AUDIT_VIEW
F-15 LOW Livewire Auth Gap App\Livewire\SettingsCatalogSettingsTable Tenant Liest Policy-Einstellungen ohne eigene Auth Kein eigener Authorization-Check; angenommen: nur auf autorisierten Seiten gemounted Falls auf anderer Seite gemounted, Daten-Leak möglich Defensive Auth prüfen oder Assert bei mount()

4. Mismatch Matrix

Dimension Status Details
Navigation Visibility ↔ Policy Enforcement Konsistent für Tenant-Panel Navigation items nutzen canViewAny() + Policy-Checks; UiEnforcement erzwingt Dreischicht-Modell
Navigation Visibility ↔ Policy Enforcement ⚠️ Inkonsistent für Monitoring-Pages Operations und AuditLog sind shouldRegisterNavigation=false aber per URL erreichbar ohne canAccess()
Navigation Visibility ↔ Policy Enforcement ⚠️ Inkonsistent für System-Panel System-Pages haben nur DIRECTORY_VIEW/OPERATIONS_VIEW Capability, aber zeigen Daten aller Mandanten
Query/Data Scope ↔ Navigation Scope Konsistent für Tenant-scoped Resources getEloquentQuery() filtert konsequent nach Tenant::current()
Query/Data Scope ↔ Navigation Scope Konsistent für Workspace-scoped Resources getEloquentQuery() filtert nach WorkspaceContext::currentWorkspaceId() mit whereRaw('1 = 0') als Fallback
Query/Data Scope ↔ Navigation Scope ⚠️ System-Widgets: Kein Scope, Navigation erlaubt ControlTower-Widgets haben weder Query-Scope noch Navigation-Gate
Route Accessibility ↔ Authorization Tenant Panel Seiten Middleware-Stack (ensure-workspace-selected, ensure-filament-tenant-selected, DenyNonMemberTenantAccess)
Route Accessibility ↔ Authorization Tenantless Run Viewer mount()$this->authorize('view', $run) → OperationRunPolicy prüft Workspace+Tenant+Capability
Route Accessibility ↔ Authorization ⚠️ AuditLog Page shouldRegisterNavigation=false, aber kein canAccess() — per URL erreichbar
Action Auth ↔ Bulk Action Auth Konsistent UiEnforcement erzwingt all-or-nothing Semantik für Bulk Actions mit gleicher Capability wie Single Actions
Widget Data ↔ User Scope Dashboard-Widgets DashboardKpis, NeedsAttention, RecentOperations nutzen Filament::getTenant() korrekt
Widget Data ↔ User Scope AlertsKpiHeader Filtert nach workspace_id + user.tenantMemberships + optional activeTenant
Widget Data ↔ User Scope ⚠️ ControlTower-Widgets Keine Scope-Filterung — zeigen Platform-weite Aggregate
Global Search ↔ Scope ScopesGlobalSearchToTenant Trait Prüft canAccessTenant() und filtert per whereBelongsTo()
Global Search ↔ Scope ⚠️ Trait-Nutzung verifizieren Unklar ob alle globalsuchbaren Resources diesen Trait nutzen
Relation Managers ↔ Parent Scope Konsistent TenantMembershipsRelationManager, BackupItemsRelationManager etc. erben Parent-Scope des owning Resource
Deep Links ↔ Auth Notification-URLs OperationRunPolicy prüft Workspace+Tenant bei mount()
Deep Links ↔ Auth ⚠️ IDs in URLs Sequential integers ermöglichen Enumeration

5. Target Enterprise RBAC Model

Rollen-/Capability-Modell (Zielzustand)

Platform Layer
├── Platform Admin: Full system access
├── Platform Ops:   Operations monitoring (scoped)
├── Platform Audit: Security audit view only
└── Platform Support: Break-glass + Directory (audited, 4-eyes for critical)

Workspace Layer
├── Owner:    Full workspace control + all tenant capabilities
├── Manager:  Workspace admin (no archive/delete) + most tenant capabilities
├── Operator: Execute operations + view
└── Readonly: View-only

Tenant Layer
├── Owner:    Full tenant control
├── Manager:  Admin (no delete/membership manage)
├── Operator: Execute sync/backup/run + view
└── Readonly: View-only

Regeln für Navigation Visibility

  1. Navigation zeigt NUR Items, für die der Nutzer authorization hat — sowohl shouldRegisterNavigation() als auch canAccess() müssen konsistent sein
  2. Hidden Pages müssen canAccess() implementierenshouldRegisterNavigation=false bedeutet nicht "keine Autorisierung nötig"
  3. System-Panel Navigation muss capability-granular sein — nicht eine einzige CONSOLE_VIEW Capability für alles
  4. Navigation darf niemals die einzige Schutzschicht sein

Regeln für Query Scope

  1. Jede getEloquentQuery() muss scope-aware sein — mit whereRaw('1 = 0') als Fallback bei fehlendem Kontext
  2. Tenant-scoped Modelle nutzen DerivesWorkspaceIdFromTenant oder $tenantOwnershipRelationshipName
  3. Workspace-scoped Modelle filtern nach WorkspaceContext::currentWorkspaceId()
  4. System-Queries (ControlTower) müssen entweder scope-kompartimentiert oder anonymisiert sein
  5. AuditLog muss workspace_id als strukturelles Scope-Feld haben

Regeln für Direct URL Access

  1. Jede Page muss canAccess() implementieren — keine Ausnahme für "hidden" Pages
  2. Route Model Binding muss Scope-Ownership erzwingen — OperationRunPolicy-Muster als Standard
  3. UUID-basierte Route-Keys für sensitive Ressourcen — Findings, OperationRuns
  4. Rate-Limiting auf Detail-Endpoints — gegen Enumeration

Regeln für Actions / Bulk Actions

  1. UiEnforcement ist der Standard für alle Actions — kein Bypass
  2. Destructive Actions: ->requiresConfirmation() + ->action(...) + Capability-Check
  3. Bulk Actions: all-or-nothing Semantik (bereits implementiert)
  4. Keine Action darf schwächer autorisiert sein als die entsprechende Single-Record-Action
  1. Widgets dürfen nur scope-konforme Daten anzeigen — kein Count über unerlaubte Scopes
  2. Global Search muss ScopesGlobalSearchToTenant nutzen — für alle tenant-scoped Resources
  3. Deep Links in Notifications müssen Policy-geschützt sein — bereits implementiert, UUID-Keys evaluieren
  4. Export-Funktionen müssen dieselbe Scope-Filterung wie die UI anwenden

6. Hardening Recommendations

Quick Wins (P0-P1, sofort umsetzbar)

# Maßnahme Nutzen Risiko Aufwand Priorität
QW-1 canAccess() auf Operations.php implementieren — WorkspaceCapabilityResolver + Membership Check Schließt Page-Level Auth Lücke Minimal: bestehende Pattern kopieren 1h P1
QW-2 canAccess() auf AuditLog.php implementieren Wie QW-1 Minimal 1h P1
QW-3 System-Panel Capability-Granularisierung: OPERATIONS_VIEW in OPS_VIEW_RUNS, OPS_VIEW_FAILURES, OPS_VIEW_STUCK aufteilen Feinere Zugriffskontrolle Migration + PlatformUser Capability-Update 4h P1
QW-4 ControlTower-Widgets: Option für anonymisierte/aggregierte Ansicht Verhindert Tenant-Namen-Leak Widget-Refactor 4h P1
QW-5 SettingsCatalogSettingsTable Livewire: Defensive Auth in mount() Verhindert Context-Leak bei Wiederverwendung Minimal 30min P2

Mittlere Hardening-Maßnahmen (P2, geplant)

# Maßnahme Nutzen Risiko Aufwand Priorität
MH-1 AuditLog Migration: workspace_id Spalte + NOT NULL + Index Strukturelles Workspace-Scoping Backfill-Migration nötig 8h P2
MH-2 DerivesWorkspaceIdFromTenant auf OperationRun-Model Immutabilitäts-Garantie Sehr gering 2h P2
MH-3 DerivesWorkspaceIdFromTenant auf BaselineProfile-Model Wie MH-2 Gering 2h P2
MH-4 UUID-basierte Route-Keys für Finding, OperationRun Verhindert ID-Enumeration Model+Migration+Route-Refactor 12h P2
MH-5 Rate-Limiting auf /admin/operations/{run} und ähnliche Detail-Endpoints Anti-Enumeration Middleware-Config 2h P2
MH-6 System-Panel Directory: Capability DIRECTORY_MANAGE vs DIRECTORY_VIEW differenzieren Least-Privilege im System-Panel Capability-Registry Update 4h P2
MH-7 Break-Glass: 4-eyes-Prinzip oder temporal scoping verschärfen Privileged-Access-Governance UX-Design nötig 8h P2

Strukturelle Refactors (P3, Spec-gesteuert)

# Maßnahme Nutzen Risiko Aufwand Priorität Spec?
SR-1 Global Scope auf OperationRun für automatisches Workspace-Scoping Präventiv gegen zukünftige Query-Fehler Model-Behavior-Änderung; Tests nötig 16h P3 Ja
SR-2 System-Panel Kompartimentierung: Scope-basierte Platform Views Enterprise isolation für managed-service Betrieb Architektur-Refactor 40h P3 Ja
SR-3 Einheitliche canAccess() Base-Mixin für alle Pages DRY + Konsistenz Base-Class Refactor 16h P3 Ja
SR-4 Monitoring-Pages: Unified OperateHub Authorization Layer Konsolidierte Auth statt Page-for-Page Architektur 24h P3 Ja

7. Project Rules

Verbindliche Enterprise RBAC Rules

  1. Navigation ist nie die Sicherheitsgrenze. Jede Filament-Page muss eine canAccess() Methode implementieren, die unabhängig von Navigation Visibility autorisiert. shouldRegisterNavigation=false ersetzt keinen Authorization-Check.

  2. Jede sichtbare Aktion braucht deckungsgleiche Server-Autorisierung. UiEnforcement (Tenant) oder WorkspaceUiEnforcement (Workspace) ist der Standard-Wrapper für alle Actions. Kein Action-Handler darf ohne Server-Side Guard ausgeführt werden.

  3. Hidden Pages dürfen nicht unautorisiert per URL erreichbar sein. Jede Page mit shouldRegisterNavigation=false oder isDiscovered=false MUSS explizit canAccess() implementieren.

  4. Workspace- und Tenant-Scope müssen in Query, Route Binding und Policy konsistent erzwungen werden. Scope-Enforcement findet auf mindestens zwei Ebenen statt: Query-Level (getEloquentQuery()) UND Policy/Gate-Level.

  5. Widgets, Counts und Search dürfen keine scope-fremden Metadaten leaken. Jedes Dashboard-Widget muss denselben Scope-Filter anwenden wie die zugehörige Tabelle/Resource. System-Widgets müssen scope-kompartimentiert oder anonymisiert sein.

  6. Bulk Actions dürfen nie schwächer autorisiert sein als Single Actions. UiEnforcement erzwingt all-or-nothing Semantik: Wenn ein Record in der Selektion die Capability verletzt, wird die gesamte Bulk-Action blockiert.

  7. Deep Links und Notifications müssen kanonisch und permission-sicher sein. Jede URL, die per Notification, E-Mail oder API-Response geteilt wird, muss bei Zugriff denselben Auth-Check durchlaufen wie der UI-Pfad.

  8. Route Model Binding muss Scope-Ownership erzwingen. Policies müssen bei view() immer Workspace-Membership UND Tenant-Membership (falls tenant-scoped) prüfen. Non-Members erhalten 404 (deny-as-not-found), nicht 403.

  9. Capability-first vor rollen-/UI-getriebener Logik. Autorisierung leitet sich aus Capabilities ab, nicht aus Rollen-Strings oder UI-Zustand. RoleCapabilityMap ist die Single Source of Truth.

  10. Kein Zugriff über "zufällig funktionierende" indirekte Pfade. Jeder neue Pfad (Relation Manager, Tab, Widget, Global Search, Export) muss explizit scope-geprüft werden. Filament Auto-Discovery allein ist keine Autorisierung.

  11. Modelle mit Tenant- oder Workspace-Zugehörigkeit MÜSSEN Immutabilitäts-Traits nutzen. DerivesWorkspaceIdFromTenant oder vergleichbare Traits stellen sicher, dass Scope-Zuweisungen nach Creation nicht verändert werden können.

  12. System-Panel Capabilities müssen granular sein. Eine einzige CONSOLE_VIEW Capability für cross-workspace Sichtbarkeit reicht für Enterprise-Betrieb nicht aus. Differenzierung in Operations, Directory, Security, Break-Glass.

  13. Destructive Actions erfordern immer ->requiresConfirmation(). Keine Ausnahme, auch nicht bei "schnellen" Aktionen wie Archive oder Toggle.

  14. AuditLog muss workspace-scoped sein. Jeder Audit-Eintrag muss workspace_id tragen, um cross-workspace Reporting und Compliance zu ermöglichen.


8. Spec Proposal Backlog

Spec A: System Panel Kompartimentierung

Feld Wert
Titel System Panel Capability Granularization & Data Compartmentalization
Problem Alle PlatformUser mit CONSOLE_VIEW sehen Betriebsdaten aller Workspaces/Tenants. ControlTower-Widgets, Directory-Pages und Access-Logs bieten keine Scope-Isolation.
Ziel PlatformCapabilities aufteilen in OPS_VIEW_RUNS, OPS_VIEW_FAILURES, DIRECTORY_VIEW_TENANTS, DIRECTORY_VIEW_WORKSPACES, SECURITY_AUDIT_VIEW. ControlTower-Widgets anonymisieren oder scope-kompartimentieren.
Scope System Panel Widgets, Directory Pages, Access Logs, PlatformCapabilities Registry
Non-goals Nicht: Umbau der web-Guard-Architektur; nicht: Multi-Panel Redesign
Priorität P1 — Enterprise-Compliance-Risiko
Abhängigkeiten Keine

Spec B: Page-Level Authorization Enforcement

Feld Wert
Titel Enforce canAccess() on all Filament Pages
Problem Mehrere Pages (Operations, AuditLog, potentiell weitere) haben keinen expliziten canAccess() Check und verlassen sich nur auf Middleware
Ziel Alle Pages im Admin/Tenant/System Panel implementieren canAccess() mit CapabilityResolver/WorkspaceCapabilityResolver
Scope Alle Filament Pages; PHPStan oder Pest-Regel zur Enforcement-Prüfung
Non-goals Nicht: Middleware-Umbau; nicht: UiEnforcement-Refactor
Priorität P1 — Defense-in-Depth
Abhängigkeiten Keine

Spec C: AuditLog Workspace Scoping

Feld Wert
Titel Add workspace_id to AuditLog for Structural Scope Isolation
Problem AuditLog hat nur tenant_id, kein workspace_id. Query-Level-Scoping ist fragil und kann bei neuen Zugangspfaden umgangen werden.
Ziel Migration: workspace_id Spalte (nullable → later NOT NULL); Backfill-Job; DerivesWorkspaceIdFromTenant-Trait; Index
Scope AuditLog Model, Migration, Backfill, Audit-Service Updates
Non-goals Nicht: AuditLog Schema-Redesign; nicht: Retention-Policy
Priorität P2
Abhängigkeiten Keine

Spec D: Model Immutability Enforcement

Feld Wert
Titel Apply DerivesWorkspaceId Trait to OperationRun, BaselineProfile, AlertRule
Problem OperationRun, BaselineProfile, AlertRule haben keine Model-Level Immutabilitäts-Garantie für workspace_id. Scope-Zuweisungen könnten theoretisch nach Creation verändert werden.
Ziel DerivesWorkspaceIdFromTenant oder DerivesWorkspaceIdFromTenantWhenPresent Trait auf alle scope-relevanten Modelle anwenden; WorkspaceIsolationViolation als Guard
Scope OperationRun, BaselineProfile, AlertRule, AlertDestination Models
Non-goals Nicht: Global Scope Enforcement (separate Spec)
Priorität P2
Abhängigkeiten Keine

Spec E: UUID Route Keys für Sensitive Resources

Feld Wert
Titel UUID-based Route Keys for Findings, OperationRuns, and Sensitive Records
Problem Sequential integer IDs in URLs ermöglichen Enumeration. Notification-Deep-Links und Tabellen-Links enthalten vorhersagbare IDs.
Ziel getRouteKeyName() auf external_id (UUID) umstellen für Finding, OperationRun; Migration für UUID-Spalte; URL-Refactor
Scope Finding, OperationRun, ReviewPack Models; Routes; Notification Links
Non-goals Nicht: Alle Models umstellen; nicht: bestehende DB-PKs ändern
Priorität P2
Abhängigkeiten Keine

Spec F: OperateHub Unified Authorization Layer

Feld Wert
Titel Unified Authorization Layer for Monitoring/OperateHub Pages
Problem Monitoring-Pages (Operations, Alerts, AuditLog) haben unterschiedliche Auth-Patterns. Operations nutzt kein canAccess(), Alerts nutzt WorkspaceCapabilityResolver, AuditLog nutzt keines.
Ziel Shared Trait oder Base-Page-Klasse für OperateHub-Pages mit einheitlicher canAccess() + Capability-Mapping
Scope OperateHub Pages, Monitoring Cluster, Shared Trait
Non-goals Nicht: Redesign der OperateHubShell Navigation-Logik
Priorität P2
Abhängigkeiten Spec B (Page-Level Auth Enforcement)

Spec G: Global Search Scope Verification & Trait Coverage

Feld Wert
Titel Verify and Enforce ScopesGlobalSearchToTenant Usage on All Searchable Resources
Problem ScopesGlobalSearchToTenant Trait existiert und ist gut implementiert, aber es ist unklar, ob alle global-suchbaren Resources ihn nutzen.
Ziel Audit: Welche Resources sind global-suchbar? Nutzen alle den Trait? Pest-Test für Enforcement.
Scope Alle Filament Resources mit $recordTitleAttribute oder globallySearchable
Non-goals Nicht: Redesign der Global-Search-Architektur
Priorität P2
Abhängigkeiten Keine

Appendix: Positive Architecture Highlights

Was gut funktioniert

  1. Capability-first Design mit Capabilities::all() als Single Source of Truth und dynamischer Gate-Registrierung
  2. UiEnforcement als dreilagiger RBAC-Wrapper (Visibility → Disabled → Server Guard) — Enterprise-Grade
  3. Deny-as-not-found Semantik — Non-Members bekommen 404, nicht 403 (verhindert Existence-Leaking)
  4. DerivesWorkspaceIdFromTenant Trait — Model-Level Immutabilität mit WorkspaceIsolationViolation Exception
  5. Last-Owner Guard — Verhindert Removal/Demotion des letzten Workspace/Tenant Owners
  6. Workspace 7-Step Selection Algorithm — Robust mit Stale-Session-Handling und Audit-Events
  7. Tenant Middleware Stack — 4 Middleware-Layer (correct guard → workspace selected → tenant selected → deny non-member)
  8. Break-Glass Auditing — Vollständig auditiert mit TTL, explicit start/exit, IP-Logging
  9. OperateHubShell — Konsistente Cross-Tenant-Sicht mit Membership-Validation und Entitlement-Prüfung
  10. WriteGateInterface — Hardening-Layer gegen unsichere RBAC-Zustände bei Intune-Writes

Zusammenfassung

Die Architektur zeigt ein reifes, mehrschichtiges Autorisierungsmodell, das für die meisten Enterprise-Szenarien robust ist. Die identifizierten Lücken betreffen primär:

  1. System-Panel: Unzureichende Kompartimentierung (alle PlatformUser sehen alles)
  2. Monitoring-Pages: Fehlende explizite Page-Level Auth (Defense-in-Depth Lücke)
  3. AuditLog: Fehlendes strukturelles Workspace-Scoping
  4. ID-Enumeration: Sequenzielle IDs in URLs (kein Datenleak, aber Reconnaissance-Vektor)

Keines dieser Findings ermöglicht aktuell einen direkten Daten-Leak oder Privilege-Escalation über die bestehenden Middleware- und Policy-Checks hinaus. Die Maßnahmen dienen der Enterprise-Härtung und Defense-in-Depth, nicht der Schließung aktiver Sicherheitslücken.