Pexon Consulting | 10 Min. Lesezeit | 20.04.2026
TL;DR
LlamaIndex RBAC (Role-Based Access Control) stellt sicher, dass jeder Nutzer nur die Dokumente sieht, die er sehen darf — in der Retrieval-Schicht, vor dem LLM-Call. Pexon Consulting (80 Engineers, ISO 27001, Microsoft Partner) baut das für regulierte Branchen auf Basis von Metadata-Filtering, User-Context-Injection und Audit-Trail. Referenz: eine KI-Plattform mit über 5.000 aktiven Nutzern und rollenbasiertem Zugriff auf Wartungsprotokolle, Handbücher und FAQs.
Das 500-Berechtigungen-Problem
Enterprise-RAG ohne RBAC scheitert am ersten Compliance-Audit. Wenn ein Servicetechniker in der Werkstatt A plötzlich die Kostenkalkulation von Werkstatt B sieht, ist das kein Bug — es ist ein dokumentierter DSGVO-Verstoß nach Art. 32 (Sicherheit der Verarbeitung) und bei Banken ein MaRisk-AT-4.3-Findings-Kandidat.
Wir sehen in jedem Enterprise-Projekt dasselbe Muster: Das RAG-System wird als Chatbot gebaut, die Vector-Datenbank enthält alle Dokumente der Firma, und die Zugriffskontrolle wird per Prompt-Engineering versucht („Antworte nur, wenn der Nutzer aus der Einkaufs-Abteilung kommt“). Das ist keine Sicherheit, das ist höfliche Bitte. Jeder User-Prompt, der den System-Prompt überschreibt, öffnet den Zugriff.
Bei 500 Berechtigungsklassen, wie sie in einem durchschnittlichen DAX-30-Unternehmen vorkommen, braucht man die Filter-Logik in der Retrieval-Schicht — bevor der erste Token den LLM erreicht. Genau dort setzt LlamaIndex RBAC an.
Metadata-Filtering: Die Grundmechanik
LlamaIndex bietet mit MetadataFilters die Basis-Primitive für rollenbasiertes Retrieval. Jedes Dokument im Vector Store erhält beim Ingest strukturierte Metadaten — Abteilung, Vertraulichkeitsstufe, Gültigkeitsbereich. Zur Query-Zeit filtert der Retriever auf diese Felder, bevor der Ähnlichkeits-Score berechnet wird.
Ein Minimal-Beispiel: Wartungsprotokolle einer Fertigungs-Plattform, strukturiert nach Werk, Anlagentyp und Vertraulichkeitsstufe.
# Beim Ingest pro Dokument
metadata = {
"werk": "werk-aachen", # organisatorischer Zugriff
"anlagentyp": "CNC-Fräse-Typ-7", # funktionaler Zugriff
"vertraulichkeit": "intern", # public | intern | vertraulich
"fachbereich": "wartung", # wartung | qs | konstruktion
"dokument_datum": "2026-02-14",
"freigabe_id": "QM-2026-0214-11", # Audit-Referenz
}
Und zur Query-Zeit:
from llama_index.core.vector_stores import MetadataFilters, MetadataFilter, FilterOperator
# User-Profil kommt aus dem Auth-Token (Entra ID / Keycloak)
user = {
"werk": "werk-aachen",
"rolle": "service-techniker",
"clearance": "intern",
}
filters = MetadataFilters(
filters=[
MetadataFilter(key="werk", value=user["werk"]),
MetadataFilter(key="vertraulichkeit", value="intern",
operator=FilterOperator.LTE), # public + intern sichtbar
MetadataFilter(key="fachbereich", value=["wartung", "qs"],
operator=FilterOperator.IN), # rolle-spezifisch
],
condition="and",
)
query_engine = index.as_query_engine(
filters=filters,
similarity_top_k=5,
)
Wichtiges Detail: Der Filter wird im Vector Store selbst ausgeführt, nicht im Python-Post-Processing. Qdrant, Weaviate und Azure AI Search pushen die Metadata-Bedingung direkt auf den Index, was bei Millionen Dokumenten den Unterschied zwischen „sub-second“ und „sekundenlanges Timeout“ ausmacht.
User-Context-Injection: Rolle wird automatisch zum Filter
Das manuelle Zusammenbauen von Filter-Objekten pro Query skaliert nicht. In produktiven Systemen brauchen Sie einen Layer, der aus dem authentifizierten Nutzer automatisch das passende Filter-Set generiert.
Unser Pattern dafür in LlamaIndex:
from llama_index.core.query_engine import BaseQueryEngine
class RBACQueryEngine(BaseQueryEngine):
"""Query-Engine mit automatischem User-Context-Injection."""
def __init__(self, base_engine, user_context: dict):
self.base_engine = base_engine
self.user = user_context
def _build_filters(self) -> MetadataFilters:
# Rolle → erlaubte Fachbereiche (aus Policy-Tabelle)
policy = ROLLEN_POLICY[self.user["rolle"]]
return MetadataFilters(
filters=[
MetadataFilter(key="werk", value=self.user["werk"]),
MetadataFilter(
key="vertraulichkeit",
value=self.user["clearance"],
operator=FilterOperator.LTE,
),
MetadataFilter(
key="fachbereich",
value=policy["fachbereiche"],
operator=FilterOperator.IN,
),
],
condition="and",
)
def _query(self, query_bundle):
filters = self._build_filters()
self.base_engine.update_filters(filters)
response = self.base_engine.query(query_bundle)
# Audit-Log: welcher Nutzer, welche Filter, welche Quellen
log_audit_trail(self.user, filters, response)
return response
# Nutzung
engine = RBACQueryEngine(
base_engine=index.as_query_engine(),
user_context=get_user_from_auth_token(request),
)
Der entscheidende Vorteil: Der Entwickler, der Chatbot-Features baut, berührt RBAC nicht. Die Filter-Logik sitzt eine Schicht tiefer und ist für Application-Code unsichtbar. Sicherheit wird zur Infrastruktur, nicht zur Copy-Paste-Aufgabe in jedem neuen Endpoint.
Was DSGVO, BaFin und BAIT wirklich fordern
Regulatorik verlangt bei RAG-Systemen drei konkrete Nachweise — und „wir haben RBAC eingebaut“ reicht für keinen davon.
DSGVO Art. 32 (Sicherheit der Verarbeitung). Technisch-organisatorische Maßnahmen (TOM) müssen dokumentiert sein. Konkret: Rollen-Berechtigungs-Matrix, Review-Prozess für neue Rollen, dokumentierte Zugriffs-Logik im RAG. Die Filter-Code-Logik selbst ist Teil der TOM — wir liefern sie als Teil des Audit-Pakets.
BaFin BAIT und MaRisk (für Banken). MaRisk-Novelle 2026 (AT 4.3.5) verlangt für KI-gestützte Scoring-Verfahren explizit Daten-Governance und Zugriffs-Kontrolle. Das gilt indirekt auch für KI-Chatbots, die Scoring-Daten oder Kundenakten berühren. Pflicht: ein dokumentierter Modell-Inventar-Eintrag mit Beschreibung der Zugriffs-Kontrolle und Validierung der Effektivität.
BSI-Grundschutz-Kompendium (für KRITIS). Baustein CON.10 (Entwicklung von Webanwendungen) und ORP.4 (Identitäts- und Berechtigungsmanagement) verlangen „Least Privilege“ und dokumentierte Rollenvergabe. Bei Energieversorgern und Krankenhäusern wird das im KRITIS-Audit geprüft.
Die Praxis-Konsequenz: Ein RAG-System ohne RBAC ist in regulierten Branchen nicht produktionsfähig. Und „RBAC“ bedeutet hier nicht „Login mit Passwort“ — es bedeutet Filter-Logik auf Retrieval-Ebene, Audit-Trail, und dokumentiertes Policy-Management.
Audit-Trail mit LangFuse-Observability
Ohne Audit-Trail ist RBAC nicht prüfbar. Jeder einzelne LLM-Call braucht drei Dokumentations-Artefakte: welcher Nutzer, welche Filter, welche Quell-Dokumente. LlamaIndex liefert dafür Integrationen mit LangFuse (self-hosted), OpenLLMetry oder Arize Phoenix — alle drei speichern Trace-Daten strukturiert und durchsuchbar.
Unser produktiver Stack nutzt LangFuse on-prem, integriert in die gleiche Kubernetes-Infrastruktur wie LlamaIndex und Qdrant. Die Integration ist eine Zeile Code:
from langfuse.llama_index import LlamaIndexInstrumentor
LlamaIndexInstrumentor().start()
# Ab jetzt werden alle LlamaIndex-Operationen automatisch getraced:
# - Query-Text
# - Metadata-Filter (erlaubte Werke/Rollen/Fachbereiche)
# - Retrievte Dokumente (ID, Score, Metadata)
# - LLM-Prompt und LLM-Response
# - End-to-End-Latency
# - User-ID (über Langfuse-Context)
Im LangFuse-Dashboard sehen Sie pro User-Session jede Query mit vollständigem Retrieval-Kontext. Für einen BaFin-Audit können wir damit exakt zeigen: „User X mit Rolle Service-Techniker hat am 14.02.2026 um 09:23 Query Y gestellt, Filter waren werk=werk-aachen und vertraulichkeit<=intern, Top-3-Quellen waren Dokumente Z1, Z2, Z3." Ohne diesen Layer ist RBAC Glaubenssache, nicht Nachweis.
Retention-Empfehlung: 7 Jahre für Banking (BaFin-Anforderung), 10 Jahre für Pharma (GxP), 3 Jahre für allgemeine Enterprise-Use-Cases. Der Speicherplatz ist vernachlässigbar — Metadata-Traces liegen im Bereich von wenigen KB pro Query.
Code-Snippet: Die vollständige RBAC-Pipeline
Die drei Schichten zusammengeführt — Auth → RBAC-Query-Engine → Audit-Trail:
# 1. Auth-Token aus FastAPI-Request holen (Entra ID / Keycloak)
@app.post("/query")
def query(request: QueryRequest, user: User = Depends(authenticate)):
user_context = {
"werk": user.claim("werk"),
"rolle": user.claim("rolle"),
"clearance": user.claim("clearance"),
"user_id": user.sub,
}
# 2. Policy aus Rolle → erlaubte Metadaten-Werte
policy = ROLLEN_POLICY[user_context["rolle"]]
# 3. RBAC-Query-Engine mit User-Kontext
engine = RBACQueryEngine(
base_engine=global_query_engine,
user_context=user_context,
policy=policy,
)
# 4. LangFuse-Session mit User-ID
with langfuse.trace(user_id=user_context["user_id"],
session_id=request.session_id) as trace:
response = engine.query(request.text)
# 5. Explizites Audit-Event (zusätzlich zum automatischen Trace)
trace.event(
name="rbac_query",
input={"query": request.text, "filters": engine.filters.dict()},
output={"answer": str(response),
"sources": [n.metadata for n in response.source_nodes]},
)
return {
"answer": str(response),
"sources": [n.metadata for n in response.source_nodes],
"trace_id": trace.id, # für Support-Rückfragen
}
Das Ganze passt in eine FastAPI-Route. Der Dienstleister (wir) liefert RBAC-Query-Engine und Policy-Schema, das Kunden-Team liefert die Auth-Integration und die konkrete Rollen-Policy — das hat sich als saubere Schnittstelle bewährt.
Worauf Sie bei der RBAC-Einführung achten sollten
Fünf Stolpersteine, die wir in jedem zweiten Enterprise-RAG-Projekt sehen:
- Metadata-Schema zu spät definieren. Wer erst beim zweiten Use Case merkt, dass
fachbereichauch auf Dokumenten-Ebene gebraucht wird, muss alle Dokumente neu indizieren. Das Schema gehört ans Anfang des Pilots, nicht ans Ende. - Policy als Hardcode.
if rolle == "service-techniker"führt zu unhaltbarem Spaghetti-Code. Policy in YAML oder Datenbank, versioniert, mit Review-Prozess. - Filter im Post-Processing statt im Vector Store. Fatal bei Millionen Dokumenten — die Engine reranked dann 1.000 irrelevante Treffer, bevor sie die erlaubten 3 findet.
- Audit-Trail erst beim Go-Live bauen. Audit ohne Produktions-Last ist Theorie. LangFuse-Integration gehört in den ersten Sprint, nicht in den letzten.
- Rollen-Inflation. Bei 500 Berechtigungsklassen kollabiert die Policy-Verwaltung. Cluster-Ansatz nutzen: 10–15 Hauptrollen, feinere Unterscheidung über Attribute (Standort, Clearance, Projekt).
Unsere klare Empfehlung: Nicht ohne RBAC in einen Enterprise-RAG-Rollout einsteigen. "Wir fügen das später hinzu" bedeutet in der Praxis "Wir indizieren später alle Dokumente neu und bauen den Security-Layer unter Produktions-Druck" — doppelter Aufwand, zehnfaches Risiko.
Häufig gestellte Fragen
Was kostet die RBAC-Integration in ein bestehendes LlamaIndex-Projekt?
Als Festpreis-Modul rechnen wir 25.000–45.000 EUR über 3–5 Wochen, wenn das bestehende System sauber gebaut ist (Qdrant oder Weaviate, definiertes Dokumenten-Schema). Darin enthalten: RBAC-Query-Engine, Policy-Schema, LangFuse-Integration, Audit-Trail-Dashboard. Bei einem Greenfield-Pilot mit RBAC ab Tag 1 ist der Mehraufwand gegenüber einem "Basic-RAG" rund 15–20 %.
Brauche ich LangFuse, oder reicht LlamaIndex-Built-in-Logging?
Für Pilots und interne Tools reicht LlamaIndex-Built-in plus Standard-Python-Logging. Für regulierte Produktiv-Umgebungen empfehlen wir LangFuse (self-hosted) oder Arize Phoenix — beide bieten strukturierte Trace-Speicherung mit User-Session-Aggregation, was bei Audits Standard-Anforderung ist. OpenLLMetry ist die Open-Source-Alternative, wenn Sie bereits OpenTelemetry-Infrastruktur haben.
Wie verhält sich LlamaIndex RBAC zu Azure AI Search Security Filters?
Azure AI Search bietet native Security-Trimming auf Basis von Principal-IDs. Wenn Sie bereits Azure AI Search nutzen, ist der Metadata-Filter-Layer von LlamaIndex eine zusätzliche Schicht darüber — redundant, aber nicht schädlich. Unsere Empfehlung: In reinen Azure-Stacks direkt AI Search Security Filters nutzen, in Multi-Vendor-Stacks oder on-prem-Setups die LlamaIndex-Schicht, weil sie portabel zwischen Qdrant, Weaviate, Pinecone und Azure AI Search ist.
Wie teste ich RBAC automatisiert?
Wir liefern mit jedem RBAC-Pilot eine Test-Suite: 50–100 Query-User-Paare mit erwarteten Ergebnissen ("User aus Werk A darf Dokument X nicht finden"). Die Suite läuft in der CI/CD-Pipeline und fängt Regressionen ab, bevor sie produktiv werden. In DACH-Projekten besonders wichtig, weil DSGVO-Art.-32-Nachweise regelmäßig wiederholt werden müssen.
Funktioniert LlamaIndex RBAC auch mit multimodalen RAG-Systemen?
Ja — Metadata-Filter wirken auf beide Stores (Text + Bild) gleichermaßen. Bei multimodaler RAG wird die Policy entscheidender, weil ein einzelnes Diagramm manchmal sensibler ist als der umgebende Fließtext. Wir modellieren in solchen Fällen das vertraulichkeit-Feld pro Chunk, nicht pro Dokument — sonst wird die Filterung zu grob.
Nächster Schritt
Wenn Sie gerade einen Enterprise-RAG ausrollen oder ein bestehendes System regulatorik-konform nachziehen:
Verwandte Themen
→Versicherung: KI-Beratung unter VAIT und BaFin-Aufsicht
→Fertigung & Maschinenbau: Private AI mit IP-Schutz
→RAG und AI-Dokumentensuche für Unternehmen
→AI-Readiness-Assessment — DSGVO-konforme Analyse



