DEV Community

Cover image for RAG Over Enterprise Lakehouse Data Has a Permissions Clock Problem
AI Explore
AI Explore

Posted on

RAG Over Enterprise Lakehouse Data Has a Permissions Clock Problem

TL;DR — Most RAG systems bake access control into the vector index at embedding time, treating permissions like content freshness. But permissions and content decay on completely different timescales, and conflating them creates a security lag where revoked access still returns results. The fix is separating indexing (eventually consistent) from authorization (must be synchronous and checked at query time against the lakehouse's actual governance layer).

Every RAG-over-enterprise-data writeup talks about freshness like it's one problem: how quickly do new documents show up in the index. That framing is incomplete in a way that matters a lot more than most teams realize. There are two independent clocks running in any serious RAG system — a content clock and a permissions clock — and almost every production pipeline treats them as the same clock. They aren't. They don't tick at the same rate, they don't fail the same way, and conflating them is how you end up serving a terminated contractor's confidential documents through a chatbot three weeks after their badge stopped working.

Two clocks, not one

Content freshness is forgiving. If a Q3 revenue doc gets re-embedded six hours after it lands in the lakehouse, nobody gets hurt. Worst case, someone asks about numbers that just changed and gets a slightly stale answer. That's an accuracy problem, and accuracy problems are recoverable — you can caveat the answer, cite the timestamp, or just wait for the next index run.

Permission freshness has no such grace period. The moment someone's access to a dataset is revoked — role change, offboarding, a client's NDA scope narrowing — any system that still surfaces content under that identity's query is not stale, it's leaking. There's no acceptable SLA for "we'll stop showing you confidential merger documents sometime in the next sync cycle." Content can be eventually consistent. Authorization has to be effectively synchronous.

Most RAG architectures don't make this distinction anywhere in the stack. They pull ACLs out of the lakehouse at indexing time, flatten them into metadata fields on the vector records — allowed_roles, department, classification — and then filter on that metadata at query time. That metadata is a snapshot. It was true when the embedding job ran. It is not guaranteed to be true now, and nothing in the retrieval path checks.

Why baked-in ACLs are the wrong shape

Denormalizing permissions into the vector index feels efficient. It avoids a join at query time, it's fast, and it looks like a solved problem because the filter clause is right there in the retrieval query. But it inherits every weakness of cached authorization data: it's correct until it isn't, and nothing tells you when it stops being correct.

Consider how permission changes actually propagate in a lakehouse. Unity Catalog grants, Ranger policies, row-level security tags — these live in a governance layer that changes independently of your ingestion pipeline. A revoke is an event in that system. If your vector index only re-syncs permission metadata on its regular reindex cadence — nightly, hourly, whatever — then every revoke has a blast radius equal to that cadence. A once-a-day reindex means a once-a-day security hole, every day, for every revocation that happens in between.

It gets worse with negative permissions. Granting access and then re-embedding is relatively safe — worst case, a document shows up late. Revoking access and relying on the next reindex to remove it is the dangerous direction, because the system fails open by default. Nobody designs for "my index should actively drop documents it already has," so it usually doesn't happen until someone notices, which is the wrong time to notice.

Index for retrieval, authorize at the boundary

The architectural fix is to stop treating permission filtering as a retrieval-time metadata match and start treating it as an authorization check that happens at the boundary, right before content crosses from "candidate" to "shown to the user." That means two distinct passes:

Retrieval produces candidates based on semantic relevance, with no claim about who's allowed to see them. This is the part that can be eventually consistent, cached, approximate — all the usual vector search tradeoffs apply because the cost of being wrong is a quality miss, not a security miss.

Authorization then takes those candidates and checks them against the live source of truth — the lakehouse's actual governance layer, queried synchronously, for this user, right now. Not a copy. Not a snapshot baked in at embedding time. The real grants table, the real row-level policy, evaluated at the moment of the request.

This sounds expensive, and people avoid it for that reason, but it's usually a narrow, well-indexed lookup against a governance system that's built to answer exactly this question quickly. The expensive part of RAG is the embedding search and the generation call. A permission check against a catalog's grants table for a handful of candidate document IDs is comparatively cheap, and it's the one part of the pipeline where "cheap but occasionally stale" is not an acceptable tradeoff.

The organizational version of this bug

This isn't purely a technical oversight — it's also an ownership gap. Governance teams own the ACL model in the lakehouse. ML and platform teams own the vector index and retrieval pipeline. In most organizations, these teams don't share a contract about what "permission freshness" means, so the ML team does the obvious thing: pull a snapshot of permissions at index time and treat it like any other field to be refreshed on the next ETL run.

Nobody signed off on that being the security model. It just became the security model by default, because the pipeline that builds the index is the pipeline that decided how often permissions get checked. That's backwards. The team that owns access control should be setting the consistency requirement, and the retrieval system should be built to meet it — not the other way around, where indexing cadence quietly becomes the de facto authorization SLA.

What this means for how you build the pipeline

Practically, this argues for a specific split in your lakehouse-to-RAG pipeline. Keep the vector index dumb about identity — it should know what a document is about, not who's allowed to see it. Keep a thin, fast, synchronous authorization layer that queries the governance system directly for every retrieval request, scoped to the handful of candidate documents the vector search returned. Instrument that layer separately from your indexing pipeline, with its own latency budget and its own alerting, because its failure mode is categorically different: indexing lag produces stale answers, authorization lag produces data exposure.

Freshness and permissions get talked about together so often that it's easy to assume they need the same fix: index more often, sync faster, tighten the loop. They don't. One of them needs a faster batch job. The other needs to stop being a batch job at all.

Top comments (0)