← Case studies

Case study 02

Multi-Tenant Access Scoping

Built tenant-scoped access patterns for a multi-tenant reporting service. Foundational work, and I'll say plainly where it stops.

Snowflake · SQL · dbt

Reporting queryAccount-scoped filterToday — query layermatures toNative row access policyNext step — warehouse layer

Context

A multi-tenant reporting service needed customers to only see their own data. I built account-based row scoping into the reporting queries to enforce that. This work started after the core platform was already in production, so it had to fit an existing system rather than get designed in from day one.

What I built

Row scoping keyed on account, applied consistently across the reporting layer, so a query for one tenant’s data can’t leak into another’s.

Illustrated generically, today versus the next maturity step:

-- today: query layer. correct only if
-- every query goes through this filter.
select *
from curated.orders
where account_id
  = current_setting('app.account_id');

-- next step: the warehouse enforces it,
-- not each query author.
create row access policy account_scope
  as (account_id varchar)
  returns boolean ->
  account_id
    = current_setting('app.account_id');

alter table curated.orders
  add row access policy account_scope
  on (account_id);

Where this stands honestly

This is foundational, not a mature, fully built out native warehouse-level RBAC or row-level-security implementation. I want to be direct about that rather than imply more than what’s there. It’s the right pattern to start with, and it’s not the end state a platform eventually needs as tenant count and query surface grow.

How I think about it

Access control on a data platform is something that matures in stages. You start with something correct and understandable, account-based scoping at the query layer is that. As the platform grows, that evolves toward native database-level enforcement (row access policies, and eventually more attribute-based control) so correctness doesn’t depend on every query being written right. I’d rather describe the stage I’m actually at than round up to a stage I’m not.