Skip to main content
CyborgDB Service ships with an operator-side multi-tenancy model built on cryptographic isolation: each index is wrapped by its own key, and per-user API keys hold their own wrapped data-encryption keys (DEKs). Permissions aren’t stored as a policy blob — the set of wrapped DEKs a user holds is their permission set, enforced cryptographically on every request. This page is the operator playbook: how to enable RBAC, mint and revoke users, and the constraints to be aware of.

Modes

You enable RBAC by setting the root key at startup:
Or via YAML:
cyborgdb.yaml
The root key has admin privileges; treat it like a master credential. Pick a fresh value — don’t reuse the CYBORGDB_API_KEY license key, which is a separate, non-authentication key (sending it as X-API-Key is rejected with 401).

Key kinds

When RBAC is on, the service classifies every X-API-Key request header: If CYBORGDB_SERVICE_ROOT_KEY is unset, authentication is disabled entirely — RBAC is strictly opt-in.

Provisioning users

A user is scoped to exactly one index, with a non-empty subset of {"read", "write"} permissions. Mint a user with the root key:
The api_key is returned exactly once and is never stored by the service. If you lose it, you must revoke the user and mint a new one. Hand it to the user securely (out-of-band, encrypted channel, secret store).
The user authenticates by passing cdbk_… as api_key to their Client — they need no index key of their own (the token carries the user’s key material, and the service opens the index via that user’s wrapped DEK).

Listing and revoking users

Revocation is cryptographic, not policy-based: the service erases that user’s wrapped DEK(s) for the index. On the next request, the service has nothing to unwrap for them — even a captured cdbk_… token becomes useless. There is no propagation lag.

SDK-supplied indexes

Per-user keys work on both key-management paths — KMS-backed indexes (kms_name=…) and SDK-supplied indexes (index_key=…). The index KEK is needed only at mint time, to unwrap the root DEK and re-wrap it under the new user: for KMS-backed indexes the service resolves the KEK server-side, while for SDK-supplied indexes you pass it on the create_user call (index_key in the POST body). From then on the user authenticates with their cdbk_… token alone — the service opens the index via the user’s own wrapped DEK, so no index KEK is involved on their requests, on either path. One difference remains on SDK-supplied indexes: auto-training after a user’s upsert is skipped, because the training job runs out-of-band with the index KEK and the service holds none for a provider: none index. The skip is per-caller, not per-index: a root upsert that supplies index_key still triggers auto-training on the same index. So to keep an SDK-supplied index trained under user writes, either train it explicitly with the root key (supplying index_key), upsert as root when practical, or migrate to KMS-backed (see Managing Encryption Keys → Migrating).
KMS-backed indexes stay the smoother fit for multi-tenancy: minting needs no key material in the request, and auto-training keeps working for user writes. But it is a recommendation, not a requirement.

End-to-end example

A typical operator workflow for onboarding a new tenant:
1

Provision a KMS slot

Add a registry entry to your service YAML — see KMS & BYOK.
cyborgdb.yaml
Restart the service. Look for KMS registry loaded in the logs.
2

Create the tenant's index (root)

3

Mint a user key for the tenant (root)

Hand the returned cdbk_… to the tenant out-of-band.
4

Tenant uses the index

The tenant configures their SDK client with api_key = "cdbk_…" and operates only on acme-documents. They cannot list, describe, or touch any other tenant’s index.
5

Revoke when access ends

Revocation is immediate — the tenant’s next request fails with 401.

Operational notes

  • Read vs write semantics. read covers query, get, list_ids, describe. write covers upsert, delete. Index lifecycle operations (create, train, delete_index) and user management are root-only — there’s no “delegated admin” permission.
  • KEK cache. Plaintext index KEKs live in an in-process cache for INDEX_KEK_CACHE_TTL_SECONDS (default 60s). Revoking a user is immediate and cryptographic; revoking KMS-level access to the wrap key propagates within the cache TTL.
  • Restarting the service. User keys survive restart — the wrapped DEKs are persisted alongside the index envelope. The root key is read from env/YAML on every start.

See also