AIForum.

Metadata Filtering in RAG: Permissions, Dates, and Multi-Tenant Retrieval

On this page

THE SHORT ANSWER

Metadata filtering is the retrieval-layer control that turns user identity, permissions, and dates into vector query constraints. In multi-tenant RAG, the orchestrator should apply tenant, ACL, and date filters before grounding data reaches the model. This guide explains practical patterns, implementation checks, and common failure modes.
Quick facts

Metadata filtering is the part of a retrieval-augmented generation (RAG) pipeline that turns identity, permissions, and time into query constraints. In a multi-tenant system, the orchestrator should attach filters such as tenant_id, allowed_groups, and effective_date to every vector search, so that unauthorized chunks never become grounding data for the foundation model. Microsoft’s secure multitenant RAG guidance frames the core requirement this way: tenants and individuals within tenants must only be able to incorporate grounding data they are authorized to access [1]. Amazon’s Bedrock Knowledge Bases guidance shows one scalable approach: use S3 folder structures and metadata filtering inside a single knowledge base, then rely on vector database integrations for advanced filtering and querying [2].

This article explains how metadata filtering works, how to model permissions and dates, and how to choose between separate indexes and shared multi-tenant retrieval. It is written for technical beginners and intermediate practitioners who are building or reviewing a RAG system. The examples are illustrative; they are not benchmark results or claims about a specific vendor’s performance.

What metadata filtering does in a RAG pipeline

A typical RAG pipeline connects a user to an intelligent application, then to an identity provider, then to an orchestrator. The orchestrator retrieves relevant information from databases and vector stores and passes that information as grounding data to the foundation model [1]. Metadata filtering sits between the user’s question and the vector search.

Metadata is structured information attached to each chunk or document. Common fields include:

  • tenant_id — the organization or customer that owns the data.
  • user_id, group_ids, or acl — who may read the chunk.
  • document_id, source, and version — provenance and lineage.
  • classification — for example public, internal, confidential.
  • published_at, updated_at, effective_from, effective_to, and expires_at — temporal validity.
  • language, region, or product — optional retrieval facets.

Filtering can happen before vector search (pre-filtering) or after retrieval (post-filtering). For permissions, pre-filtering is usually the safer default: the vector database restricts the candidate set before similarity scoring, so unauthorized chunks are less likely to enter the context window, logs, or caches. Post-filtering can still be useful for ranking or business rules, but it should not be the only access control layer.

Permissions: turning identity into a query filter

The orchestrator must derive permission filters from trusted identity claims, not from client-supplied parameters. A user can send a question, but the server should decide which tenant and groups that user belongs to. If the client can set tenant_id directly, a malicious or buggy client can request another tenant’s data.

A simple permission filter might look like this pseudocode:

filter = {
  tenant_id: 'acme',
  allowed_groups: { in: ['engineering', 'finance'] },
  classification: { in: ['public', 'internal'] }
}

The exact syntax depends on the vector database. The important design rules are:

  • Deny by default. If the authenticated request has no tenant claim, return no results rather than searching across all tenants.
  • Use AND for tenant isolation. Every query should include the tenant constraint, even if the user is an administrator.
  • Use OR for group access. A chunk is readable if the user belongs to at least one allowed group.
  • Validate and allowlist filter fields. Never concatenate raw user input into a filter expression. Treat filter construction like SQL query construction.
  • Keep authorization outside the model. The foundation model should not decide whether a chunk is allowed. It receives only the chunks that already passed the filter.

Microsoft’s guidance emphasizes that multitenant RAG has concerns beyond access control, but access control is the focus because cross-tenant leakage is a direct security failure [1]. The practical takeaway is that permission metadata must be complete at ingestion time. If a document has no tenant or ACL metadata, the retrieval layer cannot enforce the correct boundary later.

Dates: freshness, validity, and historical questions

Date metadata answers a different question from permission metadata: not ‘who may see this?’ but ‘which version is correct for this moment?’ In RAG systems, date filters usually fall into three categories.

Freshness

For questions about current policy, pricing, or product documentation, filter to the most recent version. A common pattern is to store updated_at as an ISO 8601 UTC timestamp and filter for documents updated within a chosen window. Be careful with time zones: store UTC and convert only for display.

Validity

Some documents are valid only between two dates. A policy might have effective_from and effective_to. A ‘current’ query should include chunks where effective_from <= now and either effective_to is null or effective_to > now. A historical query should use an as_of date supplied by the user or the application, not the current time.

Retention and expiry

Retention metadata can exclude expired content from retrieval. This is useful for compliance and for reducing noise. It is not a substitute for deleting data from the underlying store when deletion is required. Metadata filtering controls retrieval; it does not change storage lifecycle.

Date filters combine with permission filters using AND logic. For example:

filter = {
  tenant_id: 'acme',
  allowed_groups: { in: ['hr'] },
  effective_from: { lte: '2026-10-16' },
  effective_to: { gte: '2026-10-16' }
}

That filter says: show Acme HR documents that are effective on October 16, 2026. The date is illustrative. The important part is that the date constraint is applied in the same query as the tenant and group constraints.

Multi-tenant retrieval patterns

There is no single best multi-tenant architecture. The right choice depends on isolation requirements, operational capacity, and query patterns.

Separate index or collection per tenant

Each tenant gets its own index, collection, or database. This provides strong isolation and simplifies deletion when a tenant leaves. The tradeoffs are higher operational overhead, more indexes to monitor, and potentially higher cost. It is often chosen when contracts or regulations require physical or logical separation.

Shared index with tenant metadata filtering

All tenants share one index, and every query includes a tenant_id filter. This is efficient and easier to scale for many small tenants. The risk is misconfiguration: one query without the tenant filter can expose data. Amazon’s Bedrock Knowledge Bases example uses S3 folder structures and metadata filtering within a single knowledge base, then integrates vector databases for advanced filtering and querying [2]. That pattern can work well when ingestion pipelines reliably attach tenant metadata and the orchestrator always enforces the filter.

Namespaces or partitions

Some vector databases support namespaces, partitions, or row-level security. These sit between fully separate indexes and a shared flat index. They can reduce the chance of a missing tenant filter while keeping operational overhead lower than per-tenant indexes. Check your vector database’s documentation for the exact isolation guarantees and query syntax.

An illustrative multi-tenant scenario

Suppose Acme and Beta both use the same RAG application. An Acme employee asks, ‘What is our travel policy?’ The orchestrator authenticates the user, reads the tenant claim acme, and builds a filter with tenant_id = 'acme', the user’s group memberships, and the current effective date. The vector search returns only Acme travel policy chunks. The foundation model then generates an answer grounded in those chunks.

If the tenant filter is missing, the vector search might return Beta’s travel policy because the text is semantically similar. The model would then ground its answer in another tenant’s data. This scenario is illustrative, but it shows why negative testing matters. A useful verification step is to ingest two synthetic tenants with similar documents, then run the same question as each tenant and confirm that each answer cites only its own documents. Also test a user with no tenant claim and confirm the system returns no grounding data.

Implementation checklist

  1. Define the metadata schema before ingestion. Decide which fields are required for every chunk: tenant, ACL, dates, source, and classification.
  2. Populate metadata from authoritative sources. Derive ACLs from the source system rather than asking uploaders to type them.
  3. Authenticate and derive claims server-side. The orchestrator should map the identity provider’s claims to tenant and group filters.
  4. Apply pre-filtering in the vector query. Do not retrieve first and filter later for access control.
  5. Use AND for tenant and date, OR for groups. Keep the logic explicit and testable.
  6. Write negative tests. Verify that Tenant A cannot retrieve Tenant B’s chunks, that expired documents are excluded, and that missing claims return no results.
  7. Monitor filter failures. Log when a query has no tenant filter or when a filter returns zero results unexpectedly. Mask secrets and sensitive values.
  8. Review vector database limits. Some databases have restrictions on filter complexity, indexed fields, or the number of values in an in clause. Test with realistic group sizes.

Limitations and tradeoffs

Metadata filtering is necessary but not sufficient for secure multi-tenant RAG. It depends on accurate metadata at ingestion time. If ACLs change in the source system but the vector store is not updated, retrieval can be stale. If a document is re-ingested without tenant metadata, it may become invisible or, worse, misclassified. Complex filters can also reduce recall: a very narrow date range or a long group list may exclude relevant documents.

Shared-index patterns are operationally simpler but require strong enforcement in the orchestrator. Separate-index patterns offer stronger isolation but increase cost and maintenance. The right balance depends on your threat model, compliance obligations, and the number of tenants. Microsoft’s guidance notes that multitenant RAG has concerns beyond access control, so treat metadata filtering as one layer in a broader security design [1].

Troubleshooting common metadata filtering problems

Cross-tenant results appear

Check whether the orchestrator adds the tenant filter to every vector query. Also check ingestion: chunks missing tenant_id may match broadly. Fix by denying queries without a tenant claim and backfilling metadata.

Date filters return the wrong version

Verify that dates are stored as UTC timestamps or ISO 8601 strings, not free-form text. Check whether the filter uses the correct comparison operators and whether effective_to is null for open-ended documents.

Queries are slow after adding filters

Metadata fields used in filters often need indexes. Check your vector database’s documentation for indexed metadata fields and query limits. Reduce the number of values in group filters where possible, or precompute access scopes.

Post-filtering leaks data into logs

If unauthorized chunks are retrieved before filtering, they may appear in application logs, traces, or caches. Move access-control filters into the vector query itself.

What to do next

Start by writing down your metadata schema and the exact filter your orchestrator will build for every query. Then create a small test set with two tenants, overlapping content, and documents with different effective dates. Run positive and negative retrieval tests before connecting the system to real users. If you are using a managed service, review its metadata filtering documentation; Amazon Bedrock Knowledge Bases and Azure’s multitenant RAG guidance are two useful starting points [1][2].

If you are working through a similar design, share your vector database, metadata schema, and the negative test that failed in the Ai-Forum community. Specific error messages and query examples are more useful than general descriptions.

FAQ

Can the LLM enforce permissions in RAG?

No. The model should receive only chunks that already passed an access-control filter. Permissions should be enforced in the orchestrator and the vector query, because the requirement is that tenants and individuals only incorporate grounding data they are authorized to access [1].

Should I use one vector index per tenant or a shared index?

It depends on isolation requirements and operational capacity. Separate indexes provide stronger isolation but add overhead. A shared index with tenant metadata filtering is simpler to operate but relies on every query including the tenant filter. Amazon's Bedrock Knowledge Bases example uses a single knowledge base with metadata filtering [2].

How should I store dates for metadata filtering?

Store dates as UTC timestamps or ISO 8601 strings, and use range filters rather than free-form text. Distinguish updated_at, effective_from, effective_to, and expires_at so freshness, validity, and retention can be queried separately.

Does metadata filtering work with local vector databases?

Many local vector databases support metadata filters, but the exact syntax, indexed fields, and query limits vary. Check your database's documentation and test with realistic filter sizes before relying on it for access control.

What is the minimum metadata for multi-tenant RAG?

At minimum, each chunk should carry a tenant identifier, an ACL or group field, a document identifier, and relevant date fields. Without tenant and ACL metadata, the retrieval layer cannot enforce the correct boundary.

References

  1. https://learn.microsoft.com/en-us/azure/architecture/ai-ml/guide/secure-multitenant-rag
  2. https://aws.amazon.com/blogs/machine-learning/multi-tenancy-in-rag-applications-in-a-single-amazon-bedrock-knowledge-base-with-metadata-filtering/

Related terms

Metadata filtering
Structured query constraints applied to document chunks before or after vector search.
Multi-tenancy
One application serving multiple customers or organizations with data isolation.
Pre-filtering
Applying metadata constraints before similarity search so unauthorized chunks are not retrieved.
ACL
Access control list; metadata describing which users or groups may read a chunk.
Tenant ID
A stable identifier for the organization or customer that owns a document.
Orchestrator
The RAG component that authenticates requests, retrieves grounding data, and calls the foundation model.
Effective date
The date range during which a document version is considered valid.

Leave a Reply

Your email address will not be published. Required fields are marked *