Multi-tenancy
ScaiVault has a three-level tenancy model inherited from the ScaiLabs platform: partners, tenants, identities. Every secret, every policy, every audit entry is scoped to a tenant. Every tenant belongs to one partner.
The three levels#
Partner. Top-level account. Usually a company, a platform operator, or a reseller. Has one or more tenants.
Tenant. A workspace within a partner. Typically corresponds to an environment (dev/staging/prod) or a customer (for platforms). Has its own secrets, policies, users.
Identity. A user, service account, or group within a tenant. Identities come from ScaiKey — ScaiVault does not manage users itself.
Tenant resolution#
Every request is scoped to exactly one tenant. The tenant comes from one of three places, in priority order:
- Explicit path prefix —
/v1/t/{tenant_id}/.... Requires the caller's token to have partner-admin privileges and the target tenant to belong to the caller's partner. X-Tenant-IDheader — equivalent to the path prefix. Same auth requirements.- Token's
tenant_idclaim — the default. Your token is bound to one tenant; all your requests act as that tenant.
If the requested tenant doesn't belong to your partner, you get 403 access_denied. If the tenant doesn't exist, 404 tenant_not_found.
Tenant-scoped paths#
The common case. Your token's tenant_id claim determines scope automatically.
1 | |
Resolves to: "read app/db/password in the tenant identified by my token."
Tenants cannot see each other's secrets. A secret at app/db/password in tnt_acme_prod and one at the same path in tnt_acme_dev are entirely separate rows — same path, different tenants.
Partner-scoped paths#
Sometimes you want a secret visible to every tenant under a partner — a shared trust anchor, a partner-wide default config, a central webhook-signing key. Use the /v1/partner/secrets/* prefix:
1 2 3 4 | |
Every tenant under ptn_acme can read shared/webhook-signing-key, but only partner admins can write. Partner secrets show up in tenant-scoped lists with a "scope": "partner" marker.
Explicit tenant access#
Partner admins sometimes need to act as a specific tenant — debugging, bulk updates, automated provisioning. The /v1/t/{tenant_id}/ prefix does this:
1 2 | |
This reads from tnt_acme_prod as if you were a member. The audit log records the acting identity (the partner admin) and the target tenant. Use this for operator tasks, not for steady-state application traffic.
All endpoints (/v1/secrets/*, /v1/policies/*, /v1/audit/*, etc.) are available under the /v1/t/{tenant_id}/ prefix with identical semantics.
Roles#
ScaiKey defines a small set of admin roles that ScaiVault respects:
| Role | Scope | What it can do |
|---|---|---|
super_admin |
Platform | Manage any partner or tenant. Reserved for ScaiLabs staff. |
partner_admin |
Partner | Manage tenants under the partner, read/write partner-scoped secrets, act cross-tenant. |
tenant_admin |
Tenant | Manage policies, service accounts, rotation policies within one tenant. |
Roles are additive — a partner_admin is implicitly a tenant_admin for every tenant under their partner. A super_admin is everything.
Non-admin identities (regular users, service accounts, groups) get their access from policies, not roles. A tenant user doesn't "have tenant-admin access" unless the policies bound to them say so. See Policies and Permissions.
Cross-tenant sharing (what to do instead)#
Tenants cannot directly read each other's secrets. If you need two tenants to share a value:
- Is it really tenant-specific? Probably yes. Store it twice.
- Is it partner-wide? Use
/v1/partner/secrets/*. - Is it a live copy that must stay in sync? Use Federation with one tenant as the source of truth.
- Is this a one-off migration? Partner admin reads from tenant A, writes to tenant B, records the transfer in audit.
We deliberately don't provide "grant tenant B read access to tenant A's secret X" — it breaks the isolation contract that makes tenants meaningful.
Identity types#
| Type | Example ID | When to use |
|---|---|---|
user |
user:alice@acme.example |
A human in the admin UI or CLI |
service_account |
sa:reporting-service |
A service making API calls |
group |
group:sre |
A set of users, bound via policies |
Policies bind to any of these. A binding on a group effectively grants access to every user in that group — group membership is resolved at request time from the cached ScaiKey data.
Impersonation and on-behalf-of#
Service accounts can be configured in ScaiKey to "act on behalf of" a user. When the service account authenticates, the token's act claim names the user; ScaiVault uses the service account's scopes but credits the user in the audit log. This is useful for user-facing services that proxy calls to ScaiVault — the audit log tells you which human triggered each read.
What's next#
- Policies and Permissions — how paths, identities, and rules compose.
- Authentication — tokens and the tenant_id claim.
- Identity Reference — endpoints for the identity cache.