Production install

Create the first owner and issue user keys

Issue per-user authentication and execution permissions

What you will do

Create the first owner and workspace, then issue an API key for each user. Distinguish API key revocation from revoking a session's execution grant.

Before you begin

Complete installation and access configuration. Restrict bootstrap tokens and logs to operators. On Kubernetes, configure the Secret and catalogEnv so every replica receives the same BOOTSTRAP_TOKEN.

Steps

1. Create the first owner

Open /bootstrap in a browser and enter the fixed BOOTSTRAP_TOKEN, owner details, and workspace name. On a test-ops single-API installation without a configured token, scripts/test-ops.sh bootstrap-token prints the generated token once; running it again prints nothing, and no container log is read. Other single-API setups (such as scripts/local.sh) print it in the API startup log (docker logs <this-installation-api-container-id>). On Kubernetes with the default 2 replicas, use a fixed token in the Secret rather than relying on automatic generation. Reusing the token after the first owner exists returns 409 BOOTSTRAP_DONE. Sign in at /login.

2. Issue per-user keys

KEY="$(scripts/test-ops.sh key create <owner_id> \
  --scopes sessions:read,sessions:write,sessions:approve,sessions:control,sessions:recover)"

<owner_id> names the owner grouping this key's sessions. Choose a different value for each user. This is separate from web console accounts; do not use a workspace id.

The SDK and HTTP API connect using this server address and key (SDK installation).

On Kubernetes, use the following command.

First check the installation's context, namespace, and fullname. The werft below is the example installation name.

kubectl -n werft exec deploy/werft-api -c api -- \
  bun run apps/control-host/src/api/keys.ts create <owner_id> \
  --scopes sessions:read,sessions:write,sessions:approve,sessions:control,sessions:recover

The plaintext key appears on stdout only once; stderr reports the key id. Deliver the plaintext securely to the intended user without storing it in public logs. Per-user key owner identifiers are separate from web console accounts. Limit each API key's scopes to the tasks it needs.

3. Revocation contacts and execution grants

Tell users whom to contact to revoke a key. The operator CLI in the checkout provides:

scripts/test-ops.sh key revoke <key_id>
API_CONTAINER='<api-container-id-from-this-installation>'
docker exec "$API_CONTAINER" bun run apps/control-host/src/api/grants.ts revoke <session_id> --reason <text>
docker exec "$API_CONTAINER" bun run apps/control-host/src/api/grants.ts restore <session_id> --reason <text>

Replace API_CONTAINER with the API container id identified from this installation's status and Docker project label. On Kubernetes, prepare a checkout matching the installed version and host Bun and kubectl, then use keys:k8s and grants:k8s. Both NAMESPACE and RELEASE default to werft.

OperationEffect
key revokeBlocks subsequent API authentication with that key. It does not stop sessions already executing
grants revokeRevokes the specified session's execution grant and credentials and requests execution termination
grants restoreRestores the execution grant after execution is confirmed absent. It does not revive a revoked API key

Verify

Reading /v1/sessions with each user's key must return a response within its allowed scope; a request without a key must return 401. Revoked keys must fail authentication. Check the grants output receipt and execution state to distinguish acceptance from actual termination.

Troubleshooting

Different automatically generated bootstrap tokens on replicas can cause 401 when a request reaches another Pod. Pass the fixed token to every Pod. A missing Secret key prevents the Pod from starting. Do not use a workspace id as the CLI owner id.

Roll back

Do not reset the installation to remove an already-created first owner. Revoke incorrectly issued keys and create new ones with the correct scopes. Restore grants only after the old execution is gone.

Next steps

Model connections, SDK installation.

On this page