RAG über SharePoint, Confluence und Google Drive: Permissions-First-Architektur
Das harte Problem in Enterprise-RAG ist nicht die Retrieval-Qualität, es sind die Berechtigungen: Der Assistent darf niemals ein Dokument an Nutzer ausspielen, die es nicht sehen dürfen. Das Embedding entfernt die Access Control List, sodass eine naive Pipeline nach dem Muster "alles embedden, Top-k abrufen" auf Ähnlichkeit statt auf Autorisierung matcht und so Daten leakt. Die Lösung ist architektonisch. Erzwinge den Zugriff auf der Retrieval-Ebene, nicht im Prompt: Häng die ACL jedes Quelldokuments als versioniertes, filterbares Metadatum an jeden Chunk und filtere die Vektorsuche vor dem Retrieval nach Identität und Gruppenzugehörigkeiten des anfragenden Nutzers, sodass das Modell nur autorisierte Chunks zu sehen bekommt. Gib die Identität des Endnutzers weiter, nicht die eines Service-Accounts; speichere Gruppen-IDs, nicht Nutzer-IDs; lass Deny vor Grant gewinnen; und halte die ACLs aktuell, denn eine entzogene Berechtigung, die der Index noch nicht nachvollzogen hat, ist ein aktives Leak.
Dies ist der Implementierungs-Begleiter zu unserer RAG-Production-Readiness-Checkliste, die Per-User-Berechtigungen als das harte Sicherheitsproblem benennt. Dieser Beitrag zeigt, wie du es tatsächlich löst. Anbieterspezifische und Preview-Funktionen ändern sich schnell; prüf die verlinkten Docs erneut, bevor du baust.
Baust du einen RAG-Assistenten über deinen Dokumentenspeichern?
Kostenloses Beratungsgespräch buchenWarum Berechtigungen der schwierige Teil sind
Das Fehlerszenario in einem Satz: Das Modell formuliert eine flüssige Antwort, die auf einem Dokument basiert, das der anfragende Nutzer nie sehen durfte, weil das Retrieval auf semantische Ähnlichkeit gematcht hat und nicht auf Autorisierung. Sobald ein Dokument gechunkt und in einen gemeinsamen Index embedded ist, wandern die Eigentümer, Zugriffsstufen und Sensitivitätskennzeichnungen des Quellsystems nicht mit dem Vektor mit, sofern du sie nicht bewusst mitführst. Ein Vektorspeicher hat kein Konzept davon, wer fragt.
Microsoft 365 Copilot ist der kanonische Praxisfall. Es bricht Berechtigungen nicht, es respektiert sie. Das Problem ist, dass es Inhalte, die bereits übermäßig geteilt, aber schwer auffindbar waren, trivial auffindbar macht, sodass latentes Over-Permissioning, das niemandem aufgefallen ist, zu einer Ein-Prompt-Anfrage wird. Microsofts eigene Gegenmaßnahmen sind aufschlussreich: Werkzeuge, die riskante Inhalte aus der Reichweite des Assistenten herausziehen (Restricted Content Discovery, Data-Access-Governance-Reports), statt das Modell zu bitten, sich zu benehmen.
Was der entscheidende Punkt ist: Dem Modell zu sagen, ein Dokument nicht preiszugeben, ist keine Kontrolle. Die OWASP-Leitlinie zu Sensitive Information Disclosure stellt klar fest, dass System-Prompt-Restriktionen möglicherweise nicht eingehalten werden und durch Prompt Injection umgangen werden können. Prompt Injection ist das LLM-Risiko Nummer eins, und es kann indirekt eintreffen, versteckt in einem abgerufenen Dokument. Forscher haben eine nahezu vollständige Umgehung von Produktions-Guardrails demonstriert, und eine Prompt-Injection-Kette in Copilots Enterprise-Suche aus dem Jahr 2026 funktionierte genau deshalb, weil ein Leak-Prevention-Schutz nur für die erste Anfrage galt. Die Grenze muss die Architektur sein, nicht der Prompt.
Das Prinzip: auf der Retrieval-Ebene durchsetzen
Der Vektorspeicher darf ein unautorisiertes Dokument gar nicht erst zurückgeben, und das Modell darf es nie verarbeiten. Das erreichst du, indem du jeden Chunk zur Index-Zeit mit normalisierten, versionierten ACL-Metadaten taggst und zur Retrieval-Zeit einen Berechtigungsfilter in die Query einbaust. Das Filtern nach dem Retrieval, auf der Anwendungsebene oder im Prompt, scheitert auf zwei Wegen: Es verschwendet das Kontextfenster, indem es Dokumente abruft, nur um sie wieder zu verwerfen, und wenn die App-Logik einen Bug hat oder durch eine Injection umgangen wird, fließen die Dokumente trotzdem durch. Post-Filtering bricht außerdem leise den Recall, denn das Herausstreichen unautorisierter Chunks aus einem Top-k-Set kann dem Modell nichts mehr lassen, wenn die autorisierten Ergebnisse knapp außerhalb von k lagen. Filtere bereits bei der Suche vor, oder ruf ein Vielfaches von k ab und filtere dann.
Berechtigungsmodelle pro Quelle
Jede Quelle hat ihr eigenes ACL-Modell und ihre eigenen Fallen. Du ingestierst mit einer erhöhten Identität, die alle Inhalte und deren Berechtigungen lesen kann, normalisierst jede Quelle auf dieselbe Form und löst auf Gruppen-IDs auf.
| Quelle | Wie Berechtigungen funktionieren | Die Falle, die du behandeln musst |
|---|---|---|
| SharePoint / OneDrive (Microsoft Graph) | Berechtigungen kaskadieren von der Site zur Bibliothek zum Element; ACLs über den Item-Permissions-Endpoint mit grantedToV2 auslesen | Das Teilen einer einzelnen Datei bricht still die Vererbung; "Limited Access" ist Infrastruktur, kein Lesezugriff; Sensitivitätskennzeichnungen fügen eine zweite Schranke hinzu (der Nutzer braucht die Rechte EXTRACT und VIEW, nicht nur die SharePoint-ACL) |
| Confluence | Der effektive Lesezugriff ist die Schnittmenge aus Space-Berechtigung und Page-Restriction; View-Restrictions vererben sich auf Unterseiten | Die Cloud-Restrictions-API liefert vererbte Restrictions nicht zurück, daher musst du jeden Vorfahren durchlaufen und deren Lese-Restrictions vereinigen, sonst leakst du eingeschränkte Unterseiten |
| Google Drive | Sechs Rollen, Grantee-Typen user/group/domain/anyone; ACLs über die Permissions-Liste mit permissionDetails für die Vererbung auslesen | Shared Drives sind strikt expansiv (ein Kind kann nicht weniger Zugriff haben als sein Parent); eine Berechtigungsänderung am Parent erzeugt keinen Change-Log-Eintrag am Kind, daher musst du neu propagieren |
Ein Detail, das Teams beißt: Programmiere gegen Microsoft Graph gegen grantedToV2 und grantedToIdentitiesV2; die älteren grantedTo-Felder sind deprecated. Und die Sichtbarkeit von Berechtigungen ist selbst access-trimmed, daher braucht ein vollständiger ACL-Crawl eine Application Identity mit den richtigen Read-All-Scopes, kein delegiertes Nutzertoken.
Implementierungsmuster, die halten
- Speichere Gruppen-IDs am Chunk, nicht Nutzer-IDs. Geringere Kardinalität, und eine Mitgliedschaftsänderung braucht keine Neuindexierung, nur eine Gruppenauflösung zur Query-Zeit. Löse transitive, verschachtelte Mitgliedschaft auf der Principal-Seite auf.
- Ruf mit der Identität des Endnutzers ab. Ingestiere mit einer Service-Identität, aber filtere zur Query-Zeit mit der Identität und den Group-Claims des Endnutzers, weitergegeben über OAuth on-behalf-of. Verwende die unveränderliche Object-ID und die Group-Object-IDs für die Autorisierung, niemals einen veränderlichen Anzeigenamen. On-behalf-of funktioniert nur für Nutzer, nicht für Service Principals, daher kann eine reine Service-Account-Kette kein Per-User-Trimming leisten.
- Filtere an der ANN-Query mit einem Set-Membership-Test vor. Verwende eine Set-Funktion (im Äquivalent deines Vektorspeichers zu search.in oder einem $in-Filter) über die erlaubten Principals des Nutzers; eine lange Kette aus Gleichheits-ORs ist Sekunden langsamer. Deny gewinnt vor Grant.
- Behandle das Entra-Groups-Overage. Ist ein Nutzer in mehr als etwa 200 Gruppen, lässt das Identity-Token den Groups-Claim fallen und gibt einen Overage-Pointer aus; die Retrieval-Ebene muss das erkennen und die vollständige Liste nachladen, sonst werden Nutzer mit hoher Gruppenanzahl still under-filtered.
- pgvector mit Postgres Row-Level Security ist ein sauberes Primitiv: Eine Select-Policy hängt an jede Query, inklusive der Ähnlichkeitssuche, ein Berechtigungsprädikat an, sodass es im App-Code unmöglich zu umgehen ist. Achte auf die Latenz, denn die Policy kann mit dem approximativen Index in Konflikt geraten; mildere das mit partiellen Per-Tenant-Indizes oder Partitionierung und setze die Identity-Variable pro Request in deinem Connection-Pooler.
Es gibt eine echte Gabelung in den Empfehlungen, die man benennen sollte. Ein Lager (darunter AWS) argumentiert, dass Metadatenfilterung zur Query-Zeit allein nicht ausreicht und du die Autorisierung beim Retrieval erneut gegen die Quelle prüfen solltest, weil synchronisierte Metadaten veralten. Das andere (darunter Microsofts Referenzmuster) synchronisiert ACLs in den Index und setzt sie zur Query-Zeit mit dem Token des Nutzers durch, des Durchsatzes wegen. Es ist ein echter Trade-off: Aktualität gegen Latenz. Wähl nach der Sensibilität der Daten.
Das Aktualitätsproblem, das niemand einplant
Wenn Berechtigungen beim Ingest materialisiert werden, wird ein quellseitiger Entzug nicht automatisch propagiert, sodass ein Nutzer, dem der Zugriff entzogen wurde, ein Dokument im Index bis zur nächsten Synchronisation weiterhin sehen kann. Es gibt zwei Leak-Fenster: das Sync-Fenster zwischen einer Quelländerung und dem Index-Update sowie der Blindspot beim vererbten Scope, bei dem ein Werkzeug ACLs auf Elementen mit eindeutigen Berechtigungen aktualisiert, aber Änderungen verpasst, die aus einem Parent-Scope kamen. SharePoint braucht einen expliziten Permissions-Resync für vererbte Änderungen; Parent-Änderungen an Google Drives Shared Drives hinterlassen keinen Change-Log-Eintrag am Kind. Nutze die Change-Feeds der Quelle (Google Drives Changes-API feuert bei Berechtigungsänderungen, nicht nur bei Edits) und materialisiere entweder schneller mit Webhooks oder führe eine Live-Last-Mile-Prüfung durch, gemäß der obigen Gabelung.
Löschung ist die andere Hälfte. Das Recht auf Vergessenwerden bedeutet, auf jeder Ebene zu löschen: das Quellobjekt, jeden abgeleiteten Chunk und jedes Embedding, samt Caches. Entwirf die Chunk-IDs von Anfang an so, dass das Löschen eines Dokuments und all seiner Chunks eine günstige Operation ist. Und behandle das Embedding selbst als personenbezogene Daten: Forschung zu Embedding-Inversion hat den Großteil kurzer Quelltexte allein aus dem Vektor rekonstruiert, sodass ein Löschen, das das Embedding zurücklässt, in Wahrheit nichts vergessen hat.
DSGVO und Datenresidenz
Permissions-First-RAG bildet die DSGVO sauber ab. Datenminimierung spricht gegen das Bulk-Vektorisieren von allem Erreichbaren; ruf nur ab und embedde nur, was der Assistent braucht. Dem Rechenschaftsprinzip dient am besten ein konkretes Artefakt: ein Per-Query-Retrieval-Audit-Log, das festhält, welche Dokumente welcher Identität für welche Query ausgespielt wurden, was dir zudem erlaubt, einen vermuteten Stale-ACL-Leak im Nachhinein zu untersuchen. Und wo die Daten liegen, ist weiterhin wichtig, also route die Inferenz in eine EU-Region und schließe einen Auftragsverarbeitungsvertrag mit dem Modellanbieter, was wir in EU-Datenresidenz für KI-Apps im Jahr 2026 behandeln.
Die Referenzarchitektur, und die Anti-Pattern
End-to-End: Ingestiere jede Quelle mit einer Identität, die alle Inhalte und ACLs lesen kann; extrahiere die effektive ACL pro Element (unter Beachtung gebrochener Vererbung, Durchlaufen der Confluence-Vorfahren, Lesen der Drive-Vererbung); chunke, embedde und häng die normalisierte versionierte ACL als filterbares Metadatum an jeden Chunk; ruf mit der Endnutzer-Identität und einem verpflichtenden Berechtigungsfilter ab; generiere nur aus autorisierten Chunks; logge jede Entscheidung; und betreibe eine Aktualitäts-Schleife aus den Change-Feeds der Quelle mit explizitem Resync für vererbte Änderungen und kaskadierenden Löschungen bis zu Chunks und Embeddings.
Die Anti-Pattern, von denen die meisten reale Vorfälle sind, die nur darauf warten zu passieren: ein gemeinsamer Index ohne Berechtigungsfilter; Filtern nach dem Retrieval oder im Prompt; dem Modell zu vertrauen, dass es sich selbst zensiert; mit einer Service-Account-Identität abzurufen, was das Per-User-Trimming aushebelt; Per-User-IDs statt Gruppen-IDs zu speichern; SharePoints "Limited Access" als Lesezugriff zu behandeln; Confluence-Restrictions ohne Durchlaufen der Vorfahren zu lesen; nur SharePoint-ACLs zu spiegeln und dabei die Label-Verschlüsselung zu ignorieren; nur bei vollständigen Crawls zu aktualisieren, sodass Entzüge nachhängen; und das Quelldokument zu löschen, aber das Embedding zurückzulassen.

"Das Modell ist nicht deine Zugriffskontrolle, und der Prompt ist nicht deine Sicherheitsgrenze. Wenn ein Nutzer ein Dokument nicht lesen darf, darf der Vektorspeicher es nie zurückgeben. Alles andere, die Labels, die Aktualität, das Audit-Log, steht im Dienst dieser einen Regel."
Häufig gestellte Fragen
Wie setzt du Berechtigungen in RAG durch?
Respektiert RAG SharePoint-Berechtigungen?
Was ist Security Trimming in RAG?
Wie implementierst du Per-User-Berechtigungen in RAG?
Soll ich Nutzer-IDs oder Gruppen-IDs an jedem Chunk speichern?
Wie halte ich Berechtigungen aktuell, damit ich nach einem Entzug nicht leake?
Kann ich dem Modell nicht einfach sagen, eingeschränkte Dokumente nicht preiszugeben?
Kann pgvector Per-User-Zugriff durchsetzen?
Sind Dokument-Embeddings personenbezogene Daten unter der DSGVO?
Wie unterscheidet sich die Confluence-Berechtigungs-Ingestion?
Fazit
Enterprise-RAG über deinen eigenen Dokumentenspeichern steht und fällt mit einer Regel: Wenn ein Nutzer ein Dokument nicht lesen darf, darf der Retriever es nie zurückgeben, und das Modell darf es nie sehen. Das Embedding entfernt die ACL, dem Prompt kann man nicht zutrauen, sie wieder einzusetzen, und das Leak-Fenster nach einem Entzug ist real.
Bau also Permissions-First. Trag die ACL jeder Quelle als versioniertes Metadatum auf jeden Chunk, ruf mit der Identität des Endnutzers und einem verpflichtenden Filter ab, halte die ACLs aus den Change-Feeds der Quelle aktuell, behandle das Embedding als personenbezogene Daten und logge, was der Assistent wem gezeigt hat. Bring diese Architektur in Ordnung, und der Rest von RAG ist der einfache Teil.
Möchtest du ein Permissions-First-RAG auf deinem SharePoint, Confluence oder Drive?
Kostenloses Beratungsgespräch buchen