Appearance
10.4 — Document Management Systems and Enterprise Search
1. What is it?
Document management systems (DMS — e.g., SharePoint, Confluence, Box, Google Workspace) are where enterprises actually store and organize their documents, typically with their own permission models, version history, and search capabilities. Enterprise search is the broader capability (sometimes a dedicated product, sometimes built into a DMS) of searching across an organization's documents, often spanning multiple underlying systems. This chapter covers integrating an AI system with these existing systems, rather than building a separate, parallel document store from scratch.
2. Why does it exist?
Part 10.2 covered document processing generally; this chapter exists because DMS platforms specifically carry a critical property that a naive RAG implementation can easily overlook: their existing permission model is often the actual, authoritative source of truth for who can see what — a document in SharePoint or Confluence already has real, enforced access restrictions (specific users, specific groups) that predate and exist independently of your AI system. Building RAG on top of these documents without correctly respecting this existing permission model is one of the most serious, common security gaps in enterprise RAG deployments.
3. What problem does it solve?
It solves "how do I make an organization's existing documents searchable/retrievable by an AI system, while preserving exactly the same access restrictions that already exist in the source DMS" — not recreating a permission system from scratch, but correctly propagating and enforcing the one that already exists and that the organization already actively manages.
4. How does it work internally?
The permission-preservation problem, precisely
WRONG (a critical, common security gap):
1. Ingest ALL documents from SharePoint into your RAG index, regardless
of their SharePoint permission settings
2. Serve retrieval to any authenticated user of your AI system
3. Result: a user who couldn't see a specific SharePoint document
directly can now retrieve its content through your AI system's
RAG pipeline — a direct, serious permission bypass
RIGHT:
1. Ingest documents ALONG WITH their SharePoint permission metadata
(which specific users/groups can access each document)
2. At retrieval time, filter results to only documents the CURRENT
REQUESTING USER is authorized for, per the SOURCE SYSTEM's
permissions — not just per your AI system's own tenant-level
scoping (Part 3.4's tenant isolation is necessary but NOT
sufficient here; this requires document-level, not just
tenant-level, permission enforcement)This is a meaningfully finer-grained problem than Part 3.4/9.6's tenant isolation: tenant isolation ensures tenant A can never see tenant B's data; document-level permission preservation ensures that even within one tenant, user X (who lacks access to a specific confidential document in the source DMS) can't retrieve it through the AI system just because they're a valid, authenticated user of the same tenant — a distinct, additional layer of access control that many RAG implementations miss because they correctly implement tenant isolation and stop there, without recognizing document-level permissions as a separate, additional requirement.
Syncing permission changes over time
Permissions in a DMS aren't static — access is granted and revoked as employees change roles, projects end, or documents are reclassified. A RAG index built once from an initial ingestion, without an ongoing process to sync permission changes (not just document content changes), will drift out of sync with the source system's actual, current permission state — meaning a user whose access was revoked in SharePoint months ago might still be able to retrieve that document's content through the AI system if the permission sync hasn't kept pace, exactly Part 8.2's staleness problem applied specifically to permissions rather than content.
5. Simple mental model
Building RAG on top of a DMS without respecting its existing permissions is like photocopying every document in a company's filing cabinets — including the ones in the locked "confidential" drawer — and putting the photocopies in an unlocked, freely-browsable shared bin, on the reasoning that "well, the AI system has its own separate access control for the room the bin is in." The room-level access control (tenant isolation) doesn't substitute for respecting the original, finer-grained lock on the confidential drawer specifically — anyone allowed into the room can now read documents they were never supposed to see, regardless of how well the room's own door is secured.
6. Real-world example
A large enterprise's internal knowledge-assistant project initially built RAG over their entire Confluence instance, correctly scoped by tenant (their own single organization, so tenant isolation wasn't even the relevant concern) — but without checking individual page-level Confluence permissions, which the organization actively used to restrict certain HR, legal, and executive-strategy pages to specific small groups. The resulting assistant could retrieve and summarize content from these restricted pages for any employee who asked a sufficiently on-topic question, entirely bypassing access restrictions the organization had deliberately and carefully configured — discovered only during a pre-launch security review that specifically tested this scenario, not caught by earlier testing that had (correctly, but insufficiently) verified tenant-level isolation alone.
7. Architecture diagram
DMS (SharePoint/Confluence)document + its native permission metadata — specific users/groups authorized
RAG indexeach chunk carries not just tenant_id (Part 3.4) but also the SOURCE SYSTEM's specific authorized user/group list
Retrieval filterchecks: is the CURRENT REQUESTING USER in the authorized list per the SOURCE SYSTEM's permissions — not just "are they a valid tenant member"
8. Production considerations
- Ingest and preserve document-level permission metadata, not just tenant scoping (section 4/6) — this is a distinct, additional requirement beyond Part 3.4's tenant isolation, easy to miss precisely because tenant isolation alone often "looks" sufficient in initial testing.
- Build an ongoing permission-sync process, not just a one-time ingestion — permission changes in the source DMS must propagate to the RAG index's access-control metadata on a reasonable cadence (ideally webhook-driven, Part 10.1, for permission changes specifically, given how security-sensitive staleness is here compared to content staleness).
- Test document-level permission enforcement explicitly during security review (section 6) — don't let tenant-level isolation testing stand in for this distinct, finer-grained check.
- Decide explicitly how to handle documents with ambiguous or missing permission metadata — Part 10.2's "fail closed, default to restricted" principle applies directly here.
9. Common mistakes
- Implementing tenant-level isolation correctly and assuming this is sufficient, missing the distinct, finer-grained document-level permission requirement (section 4/6's exact gap).
- One-time permission ingestion with no ongoing sync process, allowing the RAG index's access control to drift out of sync with the source system's actual, current permissions over time.
- Not explicitly security-testing document-level permission enforcement, relying only on functional/tenant-level testing that wouldn't catch this specific gap.
- Assuming all documents in a DMS are equally accessible within an organization, when in practice most real enterprise DMS deployments have meaningful internal permission segmentation the organization actively relies on.
10. Security considerations
This entire chapter is fundamentally a security consideration, extending Part 9.6's tenant-isolation discussion with a finer-grained, document-level permission-preservation requirement specific to DMS integration — the single most important, most commonly-missed security gap in enterprise RAG deployments built on top of existing document systems.
11. Performance considerations
Document-level permission filtering adds a real query-time check beyond tenant-level filtering (Part 3.4) — implemented efficiently (e.g., permission metadata indexed alongside tenant_id for combined filtering in one query, rather than a separate post-hoc check per result) to avoid Part 3.4's post-filtering correctness trap at this finer granularity too.
12. Cost considerations
An ongoing, webhook-driven permission-sync process (section 8) has its own real infrastructure cost (Part 10.1's webhook integration cost) — a necessary investment given the security stakes of permission staleness, not an optional nicety to skip for cost savings.
13. When to use it
Any RAG system built on top of an existing DMS or enterprise content system with internal permission segmentation — which describes most real enterprise document corpora, since organizations routinely restrict access to HR, legal, financial, and strategic content even within a single tenant/organization.
14. When NOT to over-apply it
A document corpus that is genuinely, verifiably uniform in access (every document in the corpus is intended to be visible to every user who has any access at all) doesn't need document-level permission filtering beyond tenant scoping — but this uniformity should be explicitly verified with the customer, not assumed, given how commonly the opposite turns out to be true (section 6).
15. Alternatives and trade-offs
| Approach | Good for | Weak point |
|---|---|---|
| Document-level permission preservation + sync | Correctly mirrors the source system's actual access model | Real implementation and ongoing-sync engineering effort |
| Tenant-level isolation only (insufficient alone) | Simpler to implement | Misses intra-tenant permission segmentation (section 6's real gap) |
| Manually curated, separate "AI-accessible" document subset | Sidesteps the permission-sync problem entirely | Requires ongoing manual curation; doesn't scale to a full corpus |
16. Practical Python/code example
python
async def retrieve_with_document_level_permissions(
vector_store, query_embedding: list[float], tenant_id: str, current_user_groups: list[str], k: int = 5
) -> list[dict]:
"""
Retrieves documents scoped by BOTH tenant AND the current user's specific
source-system group memberships, enforcing document-level permissions
beyond tenant isolation alone.
Args:
vector_store: A vector store supporting compound metadata filtering.
query_embedding (list[float]): The query embedding.
tenant_id (str): Tenant scope.
current_user_groups (list[str]): The requesting user's authorized
groups, per the SOURCE SYSTEM's permission model.
k (int): Number of results to return.
Returns:
list[dict]: Results the user is authorized for, per BOTH tenant and
document-level source-system permissions.
"""
return await vector_store.query(
vector=query_embedding,
filter={
"tenant_id": {"$eq": tenant_id},
"authorized_groups": {"$in": current_user_groups}, # document-level check
},
top_k=k,
)17. Production-quality example
A permission-sync worker triggered by DMS webhook events, keeping document-level access-control metadata current, per section 8's recommendation:
python
import logging
logger = logging.getLogger("permission_sync")
async def handle_permission_change_webhook(document_id: str, new_authorized_groups: list[str], vector_store) -> None:
"""
Updates a document's access-control metadata in the RAG index immediately
when the source DMS reports a permission change, keeping the index's
access control from drifting out of sync with the source of truth.
Args:
document_id (str): The source document whose permissions changed.
new_authorized_groups (list[str]): The updated list of authorized groups.
vector_store: The vector store holding this document's indexed chunks.
"""
chunk_ids = await vector_store.find_chunk_ids_by_source_document(document_id)
for chunk_id in chunk_ids:
await vector_store.update_metadata(chunk_id, {"authorized_groups": new_authorized_groups})
logger.info(
"updated permissions for %d chunks from document=%s: now authorized_groups=%s",
len(chunk_ids), document_id, new_authorized_groups,
)18. Short exercise
A customer's security team asks you to demonstrate that an employee who lost access to a confidential Confluence space last week can no longer retrieve its content through your AI assistant. Using this chapter's sync architecture, describe the specific test you'd run and what would need to be true for it to pass.
19. Interview questions
- Explain the distinction between tenant-level isolation (Part 3.4/9.6) and document-level permission preservation, and why implementing only the former is a common, serious security gap.
- Why does permission staleness (an ongoing sync gap) matter more acutely than content staleness (Part 8.2) from a security perspective?
- Describe how you would test, specifically, whether a RAG system correctly enforces document-level permissions from a source DMS.
20. FDE/customer scenario
Customer's security team: "We have confidential pages in our Confluence that only certain teams can see — how do we know your AI assistant won't accidentally expose them to everyone?"
The credible, technically precise answer distinguishes tenant-level isolation (which the customer may already assume is handled) from the finer-grained document-level permission preservation this chapter centers on — describing the specific mechanism (ingesting and syncing native DMS permission metadata, filtering retrieval by the requesting user's actual, current group memberships) and, ideally, being able to demonstrate it directly with a concrete test case (section 18), is exactly the level of specificity a security-conscious enterprise customer needs to trust the deployment.
Key takeaways
- Tenant-level isolation and document-level permission preservation are distinct requirements — implementing only the former is one of the most common, serious security gaps in enterprise RAG deployments built on existing DMS platforms.
- Document-level permission metadata must be ingested alongside content and kept synced with the source system's current state, ideally via webhook-driven updates, given the security stakes of permission staleness.
- Security testing must explicitly verify document-level permission enforcement, not stop at tenant-level isolation testing.
Things you should be able to explain
- Why tenant isolation alone is insufficient for a RAG system built on a DMS with internal permission segmentation.
- Why permission staleness is a more acute security concern than content staleness.
Things you should be able to build
- A compound tenant-and-document-level permission filter, and a webhook-driven permission-sync worker.
Common mistakes
- Implementing tenant isolation and assuming it's sufficient, missing document-level permissions.
- One-time permission ingestion with no ongoing sync.
- Not explicitly testing document-level permission enforcement in security review.
Recommended next chapter
05-privacy-governance-compliance-multitenant.md