The Missing Layer
Many RAG deployments skip access control entirely — every user can retrieve every document. In enterprise settings, this means a junior employee’s query might retrieve executive compensation data, legal privileged documents, or HR records. Access control must be enforced at the vector database level, not at the LLM level.
Implementation Pattern
At ingestion: Attach security metadata (authorized users, groups, classification level) to every chunk during document processing. Metadata must propagate from parent document to all child chunks.
At query time: Authenticate the user, retrieve their permissions, and construct a metadata filter that restricts vector similarity search to authorized chunks only. The filter runs before similarity comparison.
# Access control at retrieval time
# 1. Get user permissions
user = authenticate(request)
groups = get_user_groups(user.id)
# 2. Build metadata filter
filter = {
"access_groups": {"$in": groups},
"classification": {
"$lte": user.clearance_level
}
}
# 3. Query vector DB WITH filter
results = vector_db.similarity_search(
query=user_query,
filter=filter, # ← enforced BEFORE search
top_k=5
)
Limitation: Vector databases sync permissions periodically, creating lag when source permissions change. For strong authorization, AWS recommends verifying permissions directly at the data source rather than relying solely on vector DB metadata filters.