Skip to content

โ† Blog

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