Skip to content

Access control

Karakoram accounts, roles and tokens authorize control-plane actions, independently of provider infrastructure credentials and engine-native users.

The server enforces policy; hidden UI controls are not an authorization boundary. Engine identities belong in MongoDB, RabbitMQ and Elasticsearch. Neo4j native users are described in Neo4j access. Every Community user has full administrative privileges; control-plane RBAC does not add native database roles.

Idempotency replay is scoped to the authenticated identity, operation, resource path and namespace (including namespace query parameters). A retry in another namespace cannot receive a cached secret from the original namespace. Generated unconditional additional RBAC grants are checked on the same resource before execution or idempotency replay. PostgreSQL binding rotation therefore requires both database-users:update and clusters:update. Conditional grants (privileged database roles/tags and cross-cluster OpenBao targets) are resolved against the request body or current engine state by their owning handlers. Weaviate user creation and API-key rotation recheck privileged-role access before returning cached keys; rotation resolves the user’s current native roles. Revoking clusters:update prevents privileged secret replay even while the principal retains its ordinary database-user permissions.

When OAuth for MCP is enabled, every connection requires interactive consent. Grants intersect the account’s current RBAC with approved scopes and optional namespace limits; they do not inherit browser OIDC group bindings. Settings → Connected apps lists and revokes your grants. listOAuthGrants and deleteOAuthGrant provide the same self-service API; api-tokens:read / api-tokens:delete allow administrators to manage others’ grants. Revocation invalidates every access and refresh token in the grant. OAuth connections cannot create or change API tokens; mint dedicated tokens with karactl or the web UI.

An empty account store creates admin from KARAKORAM_ADMIN_PASSWORD. Set it through a protected service secret; the security model describes the generated-password logging fallback. The initial account must change its password: sign in at the HTTPS UI, change it, then sign in again before privileged work/token creation. Changing the bootstrap environment variable later does not reset an existing account.

Rule Value/behavior
Account name 1–64 characters; starts with a letter; letters/digits/_ . @ - only
Password At least 12 Unicode characters; at most 1024 UTF-8 bytes; Argon2id hash
Self-service change Requires current password and a different new password
Admin reset May reuse current value; revokes prior authentication and forces change
Login backoff After five account/source failures: 1 second, doubling to 15 minutes; both correct/incorrect attempts receive 429 during delay

Respect Retry-After/details.retryAfterSeconds. Password errors identify currentPassword: invalid, newPassword: reused or newPassword: out_of_range; reuse does not clear forced change. Duplicate accounts return 409 already_exists. Enabled/forced-change updates refresh updatedAt independently of password changes.

Use Settings → Accounts or a private request file:

name: analyst
password: <temporary-password>
enabled: true
mustChangePassword: true
Terminal window
karactl accounts create -f account.yaml
karactl accounts list
karactl accounts get analyst
karactl accounts set analyst -f account-update.yaml
karactl accounts reset-password analyst -f password-reset.yaml
karactl accounts delete analyst

Assign roles through policy, not account fields. Self-service change is User menu → Change password, /change-password, or karactl accounts change-password -f FILE with currentPassword/newPassword. Forced-change users cannot finish CLI login’s token creation first. See local administrator recovery.

Role Grants
role:admin All resources/actions/objects; bootstrap user:admin is bound here
role:operator All actions on clusters, backups (including export), restores, database-users (including roles), operations, events, monitoring; read backup-storages, providers, namespaces
role:viewer Read operational resources, namespace metadata, storages and providers; no backup export, credentials, audit, accounts, tokens, RBAC or settings

Operator has no namespace administration, credential reveal, audit or account/token/RBAC/settings administration. It can still disrupt workloads, restore data and change engine identities.

cluster-data is separate from lifecycle and credential-reveal access: neither viewer nor operator receives it by default. Its read and write actions apply to <namespace>/<cluster>. A restricted API token must explicitly include matching cluster-data:read/cluster-data:write permission, and the owner must retain the corresponding RBAC grants. Writes also require cluster and installation opt-in; see cluster data MCP. For example, add p, user:analyst, cluster-data, read, prod/appdb to your complete policy for narrowly scoped data reads.

Defaults apply to fresh installations; upgrades retain stored policy. Operator/viewer namespace visibility requires these additions if absent from the existing complete policy:

p, role:operator, namespaces, read, **
p, role:viewer, namespaces, read, **

Without namespace-read grants the UI shows only default, even with other cluster access. Narrower grants are valid. New accounts have no automatic role; permissions accumulate through direct rules/inheritance, subject to deny overrides.

p, SUBJECT, RESOURCE, ACTION, OBJECT[, allow|deny]
g, SUBJECT, role:ROLE

CSV p rules default to allow. Subjects are user:NAME, group:OIDC_GROUP, role:NAME; g binds users/groups/roles to roles. Comments start with #. Resource/action/object use glob matching: * does not cross /, while dev/** matches dev and its objects. No allow means deny; any matching deny overrides allows across all subjects/roles.

Resource Actions / object
namespaces create on global *; read/update/delete on bare namespace; validation/rotation use update
clusters, database-users CRUD as exposed by route; <namespace>/<cluster>; database roles share database-users
cluster-credentials read reveals credentials; <namespace>/<cluster>
cluster-data read/write through the opt-in data MCP gateway; <namespace>/<cluster>; not included in viewer/operator defaults
openbao-unseal-keys reveal; <namespace>/<cluster>; independent from ordinary credential read
backups create/read/delete/export; <namespace>/<cluster>
restores, operations Route-defined actions; <namespace>/<cluster>
backup-storages CRUD; <namespace>/<storage>
events, monitoring read; <namespace>/<cluster>
audit read; cluster object, bare namespace or global *, according to record scope
accounts, api-tokens, rbac, settings, providers Route-defined actions; global *; token self-service exceptions below

OpenAPI defines route mappings. Lists, events/streams and /metrics filter/check actual objects; filters never widen access. Namespace metadata does not grant audit access. Cross-namespace source export and target permissions are documented in backups; scoped examples are in namespaces.

events:read or audit:read on <namespace>/<cluster> permits reading a cluster event, but only audit:read returns its optional details object in lists and streams; viewer/operator event access alone does not grant structured comparisons. Audit readers still receive masked sensitive values, never secrets; see audit redaction and durability.

OpenBao initialization-material reveal is administrator-only by default and uses openbao-unseal-keys:reveal, not cluster-credentials:read. Database-connection list/get requires clusters:read on OpenBao; create/delete requires clusters:update there and database-users:create / database-users:delete respectively on the target cluster. An OpenBao grant alone cannot authorize target identity changes. See OpenBao access.

Normalization at startup/submission changes object * to **; legacy bare cluster/storage/audit patterns become default/<pattern>. Bare namespace objects remain unchanged. Use dev/**, not bare dev, for namespace-wide audit; inspect the canonical policy after updates.

g, user:analyst, role:viewer
g, group:db-operators, role:production-operator
p, role:production-operator, clusters, *, prod/**
p, role:production-operator, clusters, delete, prod/critical, deny
p, role:production-operator, namespaces, read, prod
Terminal window
karactl rbac policy get
karactl rbac policy set -f complete-policy.csv
karactl rbac can --resource clusters --action delete --object prod/critical
karactl permissions

Warning: policy set consumes raw CSV and replaces the entire policy; examples above are additions, not replacements. Keep a protected copy and unrestricted administrator access.

The UI warns on missing admin assignments; confirmation does not bypass server validation. Replacement must leave a verifiable enabled account or currently verified OIDC-group identity with unrestricted administration and no denies. Invalid CSV identifies its line; rejected replacement preserves the previous policy. Keep a local break-glass administrator. A 403 identifies resource/action/object; check denies before retrying.

  1. Register a confidential client with exact callback https://example.com/api/v1/auth/oidc/callback.
  2. Set KARAKORAM_PUBLIC_URL to that HTTPS UI origin. Callback is derived; returned redirectURL is informative, not an override.
  3. Emit valid preferred_username and a groups claim containing a JSON string array, such as ["db-operators"], in the ID token. Access-token-only groups do not suffice.
  4. Configure Settings → SSO, or submit:
oidc:
enabled: true
issuerURL: https://identity.example.com/realms/production
clientId: karakoram
clientSecret: <oidc-client-secret>
scopes: [openid, profile, email, groups]
groupsClaim: groups
Terminal window
karactl settings set-oidc -f oidc.yaml
karactl settings get
  1. Add g, group:db-operators, role:operator or narrower bindings to the complete policy. Test SSO with low-privilege and operator identities while retaining local admin recovery.

Issuer URLs require HTTPS except loopback development. Client secrets are sealed/write-only; omitted/empty secrets retain the existing value only for unchanged issuer/client identity. Public settings expose groupsClaim/scopes, not usernameClaim, allowedGroups or an auto-creation toggle. Enabling OIDC enables account creation, not automatic roles.

Issuer/subject pinning prevents adopting existing local accounts through matching names. Session groups become group:<value> subjects; sign in again after identity-provider group changes. Current Karakoram policy changes apply independently. See protocol protections.

Test-only issuer instructions live in the end-to-end suite guide, not production SSO setup.

Tokens exercise their owner’s current permissions, optionally narrowed by immutable restrictions. Use a dedicated least-privilege automation account. Tokens begin kk_, are returned once and stored as SHA-256 hashes; disabled/deleted owners and forced password changes cannot retain ordinary token authority.

Password-current authenticated users may create/list/read/update/revoke their own tokens without api-tokens grants. Global read/update/delete grants permit the corresponding actions on other owners’ tokens. Creation always binds the caller; lists otherwise show only owned tokens.

name is required, trimmed, nonblank, 1–128 characters; duplicates are allowed, so revoke by unique ID. Optional expiresAt must be RFC3339 and strictly future (invalid/out_of_range errors). Creation without expiry lasts until revocation/owner invalidation; update omission preserves expiry, null removes it.

name: nightly-automation
expiresAt: "2026-12-31T00:00:00Z"
Terminal window
karactl tokens create -f token.yaml
karactl tokens list
karactl tokens delete '<token-id>' --yes

Securely capture creation’s one-time secret; later reads expose metadata only. Inject KARAKORAM_TOKEN from a secret manager, not command arguments/history. CLI login saves its own token; logout revokes it unless --local only removes local credentials. Bearers bypass CSRF, not RBAC.

lastUsedAt is best-effort, asynchronous usage metadata, not an authentication or audit guarantee. At most one usage update runs at a time with a one-second write budget; concurrent updates may be skipped when the writer is busy. Credential validity and owner permissions are still checked from persisted state on each request. Public version discovery reads its settings snapshot without waiting for the identity mutation mutex.

Browsers use rotating cookie sessions, not automation tokens; cookie/CSRF guarantees are separate from token permissions. The UI refreshes expired access automatically; network/5xx errors preserve the session and offer retry. Repeated authentication rejection after refresh signs out instead of looping. See CLI and API.

Set restrictions when creating a token through the API, CLI flags or the UI’s Restrictions section. Omitted restrictions preserve the owner’s full authority; an explicit empty object is restricted and does not permit credential reveal. Restrictions only remove authority: owner RBAC and token restrictions must both allow an action, including after policy changes.

Field Effect
readOnly Only read actions are allowed.
namespaces Allowlisted namespaces for namespace, cluster and storage objects.
clusters Exact allowlist of namespace/cluster for cluster-scoped resources only. Namespace metadata and other namespaced objects, such as backup storages, are visible in the listed clusters’ namespaces regardless of their own names. Combined namespace and cluster namespace constraints intersect.
permissions Allowlisted resource:action pairs; action may be *. Empty means all owner permissions. Names and actions are validated against the generated RBAC vocabulary.
allowCredentialReveal Defaults to false; blocks cluster-credentials and operations marked as returning secrets, including token creation.

Namespace/cluster-scoped tokens cannot access global objects. Collection routes remain available when their action is allowed, but filter each returned object. The same restrictions apply to events, SSE, metrics, operations, permission discovery and idempotent request replay. A read-only token may still be denied a read that returns credentials.

Restrictions cannot be changed with token update; mint a replacement instead. A restricted caller can mint only a subset of its own restrictions, never an unrestricted token. Token creation also requires credential-reveal permission and the route’s action/scope. Browser sessions and unrestricted tokens may choose any restrictions. A restricted caller with an expiring token must give every child token an expiry at or before its own; omitting/removing expiry is denied. Updating a token also requires its restrictions to be a subset of the caller’s and the resulting expiry to obey the same bound. A restricted caller therefore cannot rename or extend a broader sibling token. Browser sessions and unrestricted tokens retain the ordinary name/expiry update rules.

Terminal window
karactl tokens create --name inventory --read-only \
--scope-namespace prod --permission clusters:read

For MCP clients, karactl mcp config mints the right restricted token directly: read-only and optionally namespace-limited for the management endpoint, or scoped to one cluster with explicit cluster-data permissions for its data endpoint (--cluster NS/NAME). See the MCP quick start.

OIDC group grants apply to browser sessions, not tokens: token authentication uses the owner’s user/role subjects. Give automation accounts explicit user or role bindings. See ADR 0041.