Skip to content

AUTH

Authentication — how to get and use the API key

Kryton uses bearer API keys for lab and production (KRYTON_AUTH_MODE=apikey). The raw token is shown once (or stored in a local lab.token file); only a SHA-256 digest is kept in keys.json.

Mode When Client sends
disabled Local make demo only Nothing (do not expose publicly)
apikey Shared lab + production Authorization: Bearer <token>
proxy Behind SSO / reverse proxy Trusted X-Kryton-* headers

On the Kryton host (after DEPLOY-REMOTE.md or a checkout with krytonctl on PATH):

cd ~/.deployments/kryton   # or your clone
./scripts/ensure-api-keys.sh

This writes:

File Contents
~/.kryton/lab.token Raw bearer token — paste in the UI / use as KRYTON_TOKEN
~/.kryton/keys.json Hashed key file Kryton loads (sha256, role, projects)

Print the key:

cat ~/.kryton/lab.token
# or from your laptop:
ssh <user>@<host> 'cat ~/.kryton/lab.token'

Rotate (new token + new hash):

KRYTON_ROTATE_KEYS=true ./scripts/ensure-api-keys.sh
# then point KRYTON_API_KEYS_FILE at the new keys.json and restart krytond

Harden dockur / kubevirt lab units

./scripts/ensure-api-keys.sh
KRYTON_LAB_PUBLIC_HOST=<public-ip> ./scripts/harden-lab-services.sh

That enables apikey auth and usually KRYTON_LAB_AUTO_AUTH=true, so the browser can connect without pasting. CLI still needs the token from ~/.kryton/lab.token.


Lab: use the key

Browser (Apple Store chapter login)

  1. Open http://<host>:<port>/ (demo unit often :8080 or :18080; dockur lab often :7088).
  2. If auto-auth is off, the login chapters appear → Sign in → paste the bearer token → Sign in to Kryton.
  3. If auto-auth is on, the UI loads the token from GET /api/v1/lab/bootstrap (lab-only; requires KRYTON_ALLOW_INSECURE=true).
  4. Settings → Set session token reopens the login gate to replace the token for this tab.
  5. Sign out (top bar, or Settings → API access) clears this tab’s token and returns to the login chapters. With lab auto-auth, Sign out also skips auto-connect until you paste a key again (or clear sessionStorage).

Token storage: sessionStorage for this browser tab only.

CLI

export KRYTON_URL=http://<host>:7088          # or :18080 / your port
export KRYTON_TOKEN=$(cat ~/.kryton/lab.token) # on the host
# from a laptop:
# export KRYTON_TOKEN=$(ssh <user>@<host> 'cat ~/.kryton/lab.token')

krytonctl doctor
krytonctl list

curl

curl -sS -H "Authorization: Bearer $KRYTON_TOKEN" \
  "$KRYTON_URL/api/v1/me"

Public without a token: GET /api/v1, /healthz, /readyz, /metrics, /openapi.yaml.


Manual key (no ensure script)

TOKEN=$(krytonctl generate-token)
HASH=$(krytonctl hash-token "$TOKEN")

sudo mkdir -p /etc/kryton
sudo tee /etc/kryton/keys.json >/dev/null <<EOF
{
  "keys": [
    {
      "name": "lab-admin",
      "sha256": "${HASH}",
      "role": "admin",
      "projects": ["*"]
    }
  ]
}
EOF
printf '%s\n' "$TOKEN" | sudo tee /etc/kryton/lab.token >/dev/null
sudo chmod 600 /etc/kryton/keys.json /etc/kryton/lab.token

# Point the unit at the file, then restart:
#   Environment=KRYTON_AUTH_MODE=apikey
#   Environment=KRYTON_API_KEYS_FILE=/etc/kryton/keys.json
sudo systemctl restart kryton   # or kryton-dockur / kryton-kubevirt

Read it later: sudo cat /etc/kryton/lab.token.

keys.json must be an object with a "keys" array (not a bare array).


Production (Helm)

TOKEN=$(krytonctl generate-token)
HASH=$(krytonctl hash-token "$TOKEN")

cat > keys.json <<EOF
{
  "keys": [
    {
      "name": "ci-admin",
      "sha256": "${HASH}",
      "role": "admin",
      "projects": ["*"]
    }
  ]
}
EOF

# Save TOKEN in your secret manager — it is not stored in the cluster.
kubectl -n kryton create secret generic kryton-auth --from-file=keys.json
helm upgrade --install kryton ./deploy/helm/kryton \
  -n kryton --create-namespace \
  -f deploy/helm/kryton/values-user.yaml

Use export KRYTON_TOKEN=<saved raw token> for krytonctl / CI. Chart details: deploy/helm/kryton/README.md · DEPLOYMENT.md.


Roles and projects

Role Typical use
viewer Read-only
operator Create / start / stop / snapshot
admin Full control

projects is a list of project names, or ["*"] for all configured projects.


Browser consoles

Iframes, new tabs and websockets cannot send an Authorization header, so the dashboard asks for a console ticket first:

curl -X POST -H "Authorization: Bearer $KRYTON_TOKEN" \
  "http://127.0.0.1:8080/api/v1/machines/$ID/console-ticket?project=default"

Any key with viewer access to the machine's project can mint one. A ticket:

  • lasts 10 minutes, and the dashboard renews it every 8;
  • is accepted as ?console_ticket= or as the HttpOnly, SameSite=Strict kryton_console cookie that the mint call sets (scoped to /api/v1/machines/{id}/, Secure over TLS);
  • only allows GET/HEAD on that one machine's /console, /console/... and /vnc paths, never other API calls;
  • is signed with a per-process key, so restarting krytond invalidates every ticket.

The console proxy strips the ticket, Authorization and Cookie before forwarding to the backend.

Troubleshooting

Symptom Fix
Login page asks for a token Auth is apikey and auto-auth is off — cat ~/.kryton/lab.token (or /etc/kryton/lab.token) and paste
401 from API/CLI Export KRYTON_TOKEN with the raw token, not the hash
parse api keys file: cannot unmarshal array Use {"keys":[…]} wrapper, not a top-level JSON array
Auto-auth does nothing Need KRYTON_LAB_AUTO_AUTH=true, KRYTON_ALLOW_INSECURE=true, KRYTON_AUTH_MODE=apikey, and KRYTON_LAB_TOKEN_FILE pointing at lab.token
Console iframe shows 401 The ticket expired or krytond restarted; reopen the console to mint a new one
Lost the raw token Rotate with KRYTON_ROTATE_KEYS=true ./scripts/ensure-api-keys.sh (old token stops working after restart)