Modes
| Mode | Enabled by | Who can call what |
|---|---|---|
| Single-key (default) | CYBORGDB_SERVICE_ROOT_KEY unset | One CYBORGDB_API_KEY has full access to everything. No user routes available. |
| RBAC | CYBORGDB_SERVICE_ROOT_KEY set | The root key has admin (mint/list/revoke users, create/train/delete indexes). Per-user cdbk_… keys are scoped to one index with read / write permissions. The legacy CYBORGDB_API_KEY is no longer accepted on index routes. |
cyborgdb.yaml
Key kinds
When RBAC is on, the service classifies everyX-API-Key request header into one of three kinds:
| Kind | Header value | What it can do |
|---|---|---|
root | CYBORGDB_SERVICE_ROOT_KEY | Full admin: create/train/delete indexes; mint/list/revoke users; all data operations. |
user | A cdbk_… token minted via POST /v1/indexes/{name}/users | Data operations on one index, gated by the read / write permission set requested at mint time. Cannot create/delete indexes or manage users. |
legacy | CYBORGDB_API_KEY | Rejected on index routes when RBAC is on. Health endpoint still works. |
CYBORGDB_SERVICE_ROOT_KEY is unset, the legacy single key keeps its full-access behavior — 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:
cdbk_… as api_key to their Client — they need no index key of their own (the service resolves the index KEK server-side).
Listing and revoking users
cdbk_… token becomes useless. There is no propagation lag.
KMS-backed constraint
Per-user keys work only against KMS-backed indexes — i.e., indexes created withkms_name=… rather than index_key=…. The reason is mechanical: a user does not hold the index key, so the service must be able to resolve it server-side from a kms.registry slot. For SDK-supplied indexes (provider: none), there is no server-side key to resolve, so per-user provisioning is not supported.
If you want multi-tenant access to an index that today uses an SDK-supplied key, migrate it to KMS-backed first (see Managing Encryption Keys → Migrating).
Mint-time provisioning still requires the index KEK to bootstrap the new user’s wrapped DEK. For KMS-backed indexes this happens server-side; for SDK-supplied indexes you’d need to pass the index key on the
create_user call, but the resulting user still wouldn’t have a path to authenticate (the service can’t resolve the KEK for their later requests). This is why the constraint exists end-to-end.End-to-end example
A typical operator workflow for onboarding a new tenant:Provision a KMS slot
Add a registry entry to your service YAML — see KMS & BYOK.Restart the service. Look for
cyborgdb.yaml
KMS registry loaded in the logs.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.Operational notes
- Read vs write semantics.
readcoversquery,get,list_ids,describe.writecoversupsert,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.
- Auditing. The service logs the kind of key (
root/user/legacy/none) on each request atINFO. Pair with structured logging to attribute index activity to users.
See also
- Per-Index KMS & BYOK — required for per-user keys.
- Environment Variables —
CYBORGDB_SERVICE_ROOT_KEY,INDEX_KEK_CACHE_TTL_SECONDS. - REST API: Create User, List Users, Delete User.