Skip to content

RBAC & Row-Level Security

SecurityRBACRow SecurityMulti-Tenant
Stable On by default · production-ready

AetheriusDB ships a complete authorization stack: named roles with granted privileges, and fine-grained row-level policies that filter which rows each user can see. Together they let you run a single shared cluster as a strict multi-tenant service, where every tenant behaves as if they had a private database — using the standard CREATE ROLE, GRANT, and CREATE POLICY SQL that operators already know.

Row-level security predicates are compiled into the query plan, so applying tenant isolation across a large table does not require a separate filtering pass on top of every query. The same SQL run by two different users returns two disjoint result sets, with no application changes.

  • Standard SQL surfaceCREATE ROLE, GRANT, and CREATE POLICY behave the way Postgres operators expect.
  • Per-tenant isolation by default — a row-level policy keyed on a session variable keeps tenants from reading each other’s rows, even when they run identical queries.
  • Column and row controls compose — combine GRANT SELECT (col1, col2) with a row policy to express “this role can read a subset of columns for a subset of rows” without hand-writing a view.

The example below creates a role, grants table access, and defines a row-level policy so every tenant only sees their own orders.

-- 1. Create a role and grant table-level privileges.
CREATE ROLE tenant_reader;
GRANT SELECT ON orders TO tenant_reader;
-- 2. Attach a row-level policy that filters by the session's tenant.
ALTER TABLE orders ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON orders
FOR SELECT
TO tenant_reader
USING (tenant_id = current_setting('app.tenant'));
-- 3. Bind a user to the role and set the tenant for this session.
GRANT tenant_reader TO alice;
SET app.tenant = 'acme';
-- 4. Same SQL, two tenants, two filtered result sets — no app changes.
SELECT id, total FROM orders WHERE total > 100;

Alice sees only orders where tenant_id = 'acme'. A user bound to a different tenant runs the same query and gets a disjoint result set — the row-level policy is applied automatically, not as something the application has to remember to add.

TermMeaning
RoleA named bundle of privileges. Users inherit privileges by membership.
PolicyA predicate attached to a table that filters rows per user, per operation.
Session variableA per-session value (for example a tenant id, via SET / current_setting) that policies can reference at runtime.
Column privilegeA GRANT that restricts a role to specific columns of a table.