Stay Updated With Latest Blogs, Industry Insights & More

The Path Is the Policy: How We Eliminated Row-Level Security Filters

Written by Alan Dennis | Jun 11, 2026 1:06:33 PM

 
 

Editor's note (2026-05-12). When this post was published, Auraa used Databricks Synced Tables (managed DLT pipelines) to mirror Delta → Lakebase. In May 2026, we replaced Synced Tables with GovernanceWriter parallel fan-out: the repository layer dual-writes to silver Delta and Lakebase as a single unit of work. The architectural decision (selective Lakebase mirroring, Delta as sole write authority) is unchanged; only the mechanism shifted from infrastructure-managed sync to application-managed fan-out. References to "Synced Tables" below now mean GovernanceWriter dual-write.

Multi-tenant data platforms face a tension that every platform team navigates differently. Every tenant wants strong isolation guarantees. Every agent, analyst, and API endpoint wants seamless retrieval. The conventional resolution is a middleware layer: row-level security filters that rewrite every query to inject a WHERE tenant_id = ? predicate.

This works. It also fails in subtle ways. A missed filter exposes cross-tenant data. A new query path that bypasses the interceptor creates a vulnerability. A direct table access skips the rewrite entirely. You end up auditing middleware rather than trusting architecture.

Auraa uses a different approach. There are no row-level filters in the critical path. Isolation is enforced by addressing, not filtering.

Three Decisions That Compound

The architecture rests on three foundational choices:

  1. Metadata is data. All platform state — user roles, tool registries, quality rules, execution logs, lineage graphs — flows through the same Bronze/Silver/Gold medallion pattern as business data. Delta Lake is the single write authority for both. There is no separate operational database.
  2. Organization is configuration. Project structure within a tenant is not hardcoded. It is a per-tenant choice — schema-per-project, catalog-per-project, or environment-catalog — resolved at runtime by TenantPathResolver into fully qualified Unity Catalog paths.
  3. Retrieval adapts to the consumer. Delta remains the sole write authority. GovernanceWriter (UC-323) dual-writes selected tables to Lakebase in the same unit of work, providing sub-second API reads and connection pooling for workloads that need them.

Each decision is independently valuable. Their compounding is what makes the architecture interesting.

Isolation by Construction

When a component calls TenantPathResolver.resolve("customer", project_id="alpha", layer="silver"), the resolver returns a fully qualified path:


# Strategy: Schema per Project
aura_tenant_acme.project_alpha_silver.customer
# Strategy: Catalog per Project aura_project_acme_alpha.silver.customer
# Strategy: Environment-Catalog, Source-Schema aura_tenant_acme_prod.crm.customer

The path encodes the tenant boundary. There is no tenant_id column to forget. There is no filter to misconfigure. A component that resolves paths correctly cannot access another tenant's data, because the other tenant's data lives at a different Unity Catalog address.

This property holds for both writes and reads. DataDuct writes ingested data to the resolved path. An agent retrieves metadata from the resolved path. The same resolver, the same isolation, applied uniformly to every operation.

One Pattern, Two Payloads

Because metadata is data, platform state and business data follow the same medallion pattern through the same tenant-scoped paths:

  • Role assignments flow through governance.tenant_principal_roles (Bronze → Silver)
  • Tool registry definitions flow through registry.tools (published by Foundra at init, read by MCP at runtime)
  • Data quality rules and results live alongside the business tables they govern

An agent asking "which tables have data quality failures?" queries the same Delta tables, through the same resolver, with the same isolation guarantees as an analyst asking "what were last month's sales?" The retrieval pattern is uniform; only the payload differs.

Write Once, Retrieve Many Ways

Delta as the single write authority doesn't mean Delta is the only retrieval surface. The Lakehouse provides multiple modes:

Consumer Retrieval Mode Latency
Spark SQL analytics Direct Delta read Seconds
Agent tool invocation SQL Warehouse via MCP Sub-second
REST API SQL Warehouse endpoint Sub-second
Auth middleware (high-concurrency) Lakebase via GovernanceWriter dual-write Read-your-own-write

The auth middleware — which must resolve tenant and role on every API request — is a perfect example. Role assignments are written to Delta (preserving the full append-only audit trail). In the same unit of work, GovernanceWriter mirrors the current-state Silver row to Lakebase. The middleware queries Lakebase for sub-second, connection-pooled point lookups. The write path and the read path are independently optimized without violating the single-source-of-truth invariant.

Environment Portability Without Code Changes

The environment-as-catalog model means dev, staging, and prod each have their own catalog, their own data, their own roles — but the same code:

aura_tenant_acme_dev.crm.customer    ← dev data, dev roles 
aura_tenant_acme_prod.crm.customer ← prod data, prod roles

Pipeline code never contains environment-specific paths. The TenantPathResolver injects the correct catalog at runtime. Quality rules defined in dev apply in prod — same rule, same resolver, different catalog. Agents tested in dev work in prod — same tool definitions, correct context from the resolver.

This is the compounding effect. Once you commit to treating organization as configuration and metadata as data, environment portability falls out naturally from the architecture rather than requiring explicit tooling to manage.

The Honest Trade-offs

The TenantPathResolver becomes critical infrastructure. A resolver bug means writes land in the wrong location. Auraa mitigates this through immutable frozen dataclass design (the resolver is a pure function over immutable inputs), exhaustive strategy testing, and factory-only construction that validates the strategy before returning an instance.

Strategy migration post-onboarding is non-trivial by design. Changing a tenant's organization strategy requires data movement, metadata re-registration, and grant re-application. The choice of strategy is foundational, not a runtime toggle. Choose carefully at onboarding.

Each Lakebase-mirrored table adds a parallel write to every mutation. Tables serving API endpoints or high-concurrency reads justify the dual-write cost. Tables consumed only by Spark batch jobs don't. The judgment isn't hard for clear cases; it requires more thought for tables with mixed access patterns. (Pre-May 2026 this was a DLT compute cost; with GovernanceWriter it's a write-latency cost paid by the mutating component.)

The Principle

Decide how to store early (metadata is data — everything goes through Delta and the medallion). Decide where to store flexibly (organization as configuration — let tenants choose the right isolation model). Decide how to retrieve pragmatically (selective sync — optimize reads for each consumer without duplicating the write path).

The result is a system that is simpler to reason about, harder to misconfigure, and more flexible for tenants with different requirements.

The path is the policy. Delta is the authority. The Lakehouse is the surface.

 

Read the full technical whitepaper.

Configurable Organization Meets the Lakehouse: How Tenant-Scoped Delta Paths Enable Single-Source-of-Truth Retrieval examines all three architectural decisions in depth, with production patterns for tool registries, metadata extraction, role-based auth, and data quality.

Read the Whitepaper  →

Frequently asked questions

How do you enforce tenant isolation on Databricks without row-level security filters?
You enforce isolation by addressing instead of filtering. Each tenant's data lives at a distinct Unity Catalog path, so a component that resolves the correct path cannot reach another tenant's data because that data sits at a different catalog address. There is no tenant_id column to forget and no WHERE-clause rewrite to misconfigure. Auraa implements this with a TenantPathResolver that returns fully qualified Unity Catalog paths at runtime, applied uniformly to every read and write.
What are the risks of row-level security filters in a multi-tenant data platform?
Row-level security filters create silent failure modes. A missed filter exposes cross-tenant data, a new query path that bypasses the interceptor opens a vulnerability, and direct table access skips the rewrite entirely. The result is that you end up auditing middleware rather than trusting the architecture. Isolation enforced through Unity Catalog addressing removes the middleware from the critical path, so the boundary holds by construction rather than by interception.
Can you get sub-second API reads from Delta Lake while keeping Delta as the single source of truth?
Yes. Delta remains the sole write authority, and selected tables are dual-written to Lakebase in the same unit of work through a component called GovernanceWriter. High-concurrency consumers such as auth middleware query Lakebase for sub-second, connection-pooled point lookups, while the full append-only audit trail stays in Delta. The write path and the read path are optimized independently without breaking the single-source-of-truth invariant.
How should you structure per-tenant projects on a Databricks lakehouse: schema per project, catalog per project, or environment as catalog?
Treat project structure as per-tenant configuration rather than something hardcoded. Auraa supports schema-per-project, catalog-per-project, and environment-catalog models, all resolved at runtime by the TenantPathResolver into fully qualified Unity Catalog paths. The trade-off worth knowing: strategy migration after onboarding requires data movement, metadata re-registration, and grant re-application, so the isolation model is a foundational choice made at onboarding, not a runtime toggle.
How do you make Databricks pipeline code portable across dev, staging, and prod?
Give each environment its own catalog with its own data and roles, and inject the correct catalog at runtime instead of writing environment-specific paths into pipeline code. With an environment-as-catalog model, the same code, the same quality rules, and the same agent definitions run unchanged across dev and prod because the resolver supplies the right catalog for each environment. Environment portability falls out of the architecture rather than requiring separate tooling to manage.
Should platform metadata live in a separate operational database or in the lakehouse?
You can keep platform metadata in the lakehouse rather than a separate operational store. Auraa treats metadata as data: user roles, tool registries, quality rules, execution logs, and lineage all flow through the same Bronze, Silver, and Gold medallion pattern as business data, with Delta Lake as the single write authority for both. An agent asking which tables have data quality failures queries the same Delta tables, through the same resolver, with the same isolation guarantees as an analyst asking about last month's sales.
What is the trade-off of mirroring Delta tables to Lakebase for low-latency reads?
Each mirrored table adds a parallel write to every mutation, so the cost is paid as write latency by the mutating component. Tables that serve API endpoints or high-concurrency reads justify that cost; tables consumed only by Spark batch jobs do not. The judgment is straightforward for clear cases and takes more thought for tables with mixed access patterns, which is why mirroring is selective rather than applied to every table.
Is this approach Databricks-native, and what do you need in place to use it?
Auraa is built natively on Databricks and assumes Unity Catalog as the governance and addressing layer, Delta Lake as the write authority, and the medallion architecture for both business and platform data. It fits teams that already run, or are committing to, a Databricks lakehouse and want tenant isolation, environment portability, and low-latency reads without a row-level-security middleware layer. Positioned simply, it is the fastest path to AI-ready data on Databricks.