06 โ Permissions
Modelโ
Permissions are grants that attach a group to a (server, database, action) with optional constraints.
group โจฏ (server, database) โจฏ action โจฏ constraints โ allowed
| Piece | Meaning |
|---|---|
| Group | An SSO group claim (e.g. backend-engineers, oncall, data-platform). Synced from IdP. |
| Server / database | Logical names from the config โ never raw hosts. |
| Action | schema_read, query_read, query_write, history_read. |
| Constraint | Per-grant overrides: require_reason, row_limit, statement_timeout_ms, allowed_schemas, denied_tables, time_window (e.g. business hours only). |
A request is allowed iff some grant matches. Denies are not explicit โ absence of a matching grant denies.
Actions in detailโ
| Action | What it unlocks |
|---|---|
schema_read | list_databases, describe_schema, sample_table (size-capped) |
query_read | run_query with read-only enforcement, explain, get_query_history |
query_write | run_query with write grants (requires the DB role to also have write privileges) |
history_read | Read your own query history. Other users' history is never readable here โ admin-only via state DB |
query_read implies schema_read. query_write implies query_read.
Worked examplesโ
Backend engineer on staging: full query, schema-read on prod.
- group: backend-engineers
grants:
- server: staging
database: "*"
action: query_read
- server: prod
database: "*"
action: schema_read
Oncall with audited prod access: query on prod, but reason required and short timeouts.
- group: oncall
grants:
- server: prod
database: "*"
action: query_read
constraints:
require_reason: true
statement_timeout_ms: 5000
row_limit: 1000
Data platform with writes to a single sandbox DB:
- group: data-platform
grants:
- server: analytics
database: sandbox
action: query_write
constraints:
require_reason: true
New hires: no entry โ no access. The default is nothing.
Worker-db rollout (issue #19). Rule: rollout stays contract-only and scan-friendly.
| Item | Value |
|---|---|
| Deployable config | config/permissions.yml |
| Zitadel groups | devs, devops, cto |
| v1 action scope | query_read only |
| Shared constraints | statement_timeout_ms: 30000, row_limit: 10000 |
| Deferred scope | Per-dev DB ownership (requires Zitadel group-per-app mapping) |
Evaluationโ
For a request (user, groups, server, db, action):
- Resolve groups from the session.
- Collect every grant matching one of the user's groups and the target
(server, db). - If no grant has an action โฅ the requested action โ
forbidden. - Merge constraints across matching grants: take the most restrictive value for each (lowest
row_limit, loweststatement_timeout_ms,require_reason= true wins, schema/table allow/deny intersected). - Apply constraints to the call.
Most-restrictive merging means you can't accidentally upgrade your access by being in two groups.
Hot reloadโ
Permission changes land via PR โ merge โ operator runs kill -HUP on the gateway (or rolling restart). Live sessions keep their existing grants snapshot until next login (matches 04-auth-sso).
Admin operationsโ
There is no in-band admin UI. Operator actions are CLI subcommands of the gateway binary, run inside the container, against the state DB:
gateway admin revoke-session <user_email>gateway admin list-active-sessionsgateway admin replay-audit <query>(for compliance investigations)
Admin commands authenticate via a separate mechanism (Unix socket / shell access), not SSO โ they're for whoever has prod shell access.