Two locks, and the hole PostgreSQL reserves for the owner

PostgreSQL lets a table's OWNER walk past its own row-level-security policies — unless you set FORCE ROW LEVEL SECURITY. And nothing stops a SUPERUSER. So tenant isolation is 2 locks, not 1.

Two locks, and the hole PostgreSQL reserves for the owner

The €100 Lakehouse — 7/12

PostgreSQL lets a table's OWNER walk past its own row-level-security policies — unless you set FORCE ROW LEVEL SECURITY. And nothing stops a SUPERUSER. So tenant isolation is 2 locks, not 1.

Hard rule since day zero: tenant_id is born at the source and never comes from a client. SSO claim → Superset RLS (lock 1) → Postgres native RLS (lock 2). If the app layer is compromised, Postgres still refuses another tenant's rows.

Each lock asserted by a test, not a diagram:

→ the serving role owns nothing and is member of nothing — pg_has_role asserted false
→ none of the 4 mart roles has rolsuper or rolbypassrls — asserted on all 4
→ the publisher cannot even DELETE or TRUNCATE the mart

Measured bonus: PUBLIC had CONNECT on every database of the shared RDS instance. Revoked on ours via migration, asserted by pgTAP. Revoking it on the platform's own DB? Filed as a platform-ask — never executed from our side.

The honest exception, written down: the RDS master can read everything. The instance's break-glass, never a serving path, not ours to change.

Defense in depth is only real when each lock is asserted by a test — including the list of what it can NOT close.

That's why tenant #2 is a template clone, not a build: isolation is structural, not procedural.

In your multi-tenant setup: if the application layer is compromised, what's the second lock — and has a test ever proven it?

Databricks · dbt · Airflow · Terraform · AWS

P.S. New tech post every Wednesday.

#100EuroLakehouse #PostgreSQL #MultiTenant

Comments