Skip to content

DevOps with the API and keys

Everything the console does is a JSON route under /api/v1 (contract §4a). OpenAPI UI at /api/docs. Authenticate with a session cookie (POST /login) or an rmn_ API key in X-Ramen-Api-Key. The console API stays HTTP in 0.3.1; what changed is how the console talks to workers: every worker call (Admin/Reload, Admin/Metrics, Health/Check, the tools/list smoke) is gRPC now (§11).

Mint an API key

API Keys page → name, role, groups → Create (shown once), or:

curl -sk -c c.txt -X POST https://<console>/login -d email=admin@ramen.local -d password='…' -o /dev/null
CSRF="X-Ramen-CSRF: $(awk '$6=="ramen_csrf"{print $7}' c.txt)"   # cookie sessions must echo the CSRF token
curl -sk -b c.txt -H "$CSRF" -H 'Content-Type: application/json' -X POST https://<console>/api/v1/api-keys \
  -d '{"name":"ci-deploy","role":"group_admin","groups":["demo"]}'
# 201 {"id":"…","key":"rmn_…"}
export RMN=rmn_…
A key can never be wider than its creator. Keep rmn_ keys in CI secrets; they are for the console only — MCP clients need rmk_ keys (see local quickstart).

API keys

Cheat sheet

C='curl -sk -H "X-Ramen-Api-Key: $RMN" -H "Content-Type: application/json"', U=https://<console>/api/v1.

Task Call
Who am I GET $U/me
Users (super admin) POST $U/users {email,password,role,groups} · GET/DELETE $U/users/{id} · POST $U/users/{id}/password
Groups POST $U/groups {name,repo_url,ref} · PUT $U/groups/{g} · DELETE $U/groups/{g} (destroys infra)
Zones (super admin) POST $U/zones {name,provider,region}
Environments POST $U/groups/{g}/environments {name,ref,zones} · PUT/DELETE …/environments/{e}
Deploy POST $U/groups/{g}/environments/{e}/deploy {canary,zone?} → 202 {id}; GET $U/jobs/{id} until ok/error (job log shows health, reload, smoke steps over gRPC)
Verbose logging POST …/environments/{e}/verbose {verbose}
Block tools (v0.3.0) PUT …/environments/{e}/blocked {blocked:[names]} then deploy
Workers GET $U/groups/{g}/zones/{z}/workers (live rows from Admin/Metrics + Health/Check) · PUT … {count,size?,allowed_sizes?}
Rebalance / IP rules POST …/zones/{z}/rebalance · PUT …/zones/{z}/ip-rules {cidrs}
Service account POST …/zones/{z}/service-account (super admin) · PUT $U/groups/{g}/sa-restrictions {rules}
Permission requests POST $U/requests {group,zone,permission} · GET $U/requests · POST $U/requests/{id}/approve
Secrets POST $U/groups/{g}/secrets {name,value,env?,zone?} · GET (names) · DELETE …/secrets/{id}
MCP keys POST $U/groups/{g}/mcp-keys {name} → {key:"rmk_…"} · DELETE …/mcp-keys/{id}
API keys POST $U/api-keys {name,role?,groups?} · DELETE $U/api-keys/{id}
Logs GET $U/logs?group=&zone=&worker=&tail=500&download=1 (text/plain)
Audit / dashboard GET $U/audit · GET $U/dashboard
Backups (super admin) POST $U/backups {target:"local"|"bucket"} → {id,release_version} · GET $U/backups/{id}/download · POST $U/backups/{id}/restore
Config (super admin) GET $U/config · POST $U/config/reload · GET|PUT $U/config/sa-rules · PUT $U/config/auth · POST $U/refresh

A CI deploy job

JOB=$(eval $C -X POST $U/groups/demo/environments/prod/deploy -d "'{\"canary\":true}'" | python3 -c 'import sys,json;print(json.load(sys.stdin)["id"])')
for i in $(seq 1 150); do
  S=$(eval $C $U/jobs/$JOB | python3 -c 'import sys,json;print(json.load(sys.stdin)["status"])')
  [ "$S" = ok ] && echo PASS && exit 0; [ "$S" = error ] && { eval $C $U/jobs/$JOB; exit 1; }; sleep 2
done; echo timeout; exit 1

Talking to a worker directly (gRPC)

The console is the normal path, but the worker's admin surface is reachable with any gRPC client from inside RAMEN_ADMIN_CIDRS (locally localhost:8080; in a cluster kubectl -n ramen-<g>-<z> port-forward svc/worker 8080). Run from the repo root so -proto resolves:

grpcurl -plaintext -H "x-ramen-admin-key: $RAMEN_ADMIN_KEY" -import-path proto -proto ramen/v1/admin.proto \
  localhost:8080 ramen.v1.Admin/Metrics | python3 -c 'import sys,json,base64;print(base64.b64decode(json.load(sys.stdin)["json"]).decode())'
# {"inflight":0,"total":12,"errors":0,"load":"low","sidecar_alive":true,"loaded_at":"…","packages":{…}}
grpcurl -plaintext -H "x-ramen-admin-key: $RAMEN_ADMIN_KEY" -import-path proto -proto ramen/v1/admin.proto \
  localhost:8080 ramen.v1.Admin/Reload                          # re-sync bucket, pip install if needed, runtime.load
grpc_health_probe -addr localhost:8080                          # SERVING / NOT_SERVING, no key needed
Without the key: Unauthenticated; from outside the admin CIDRs: PermissionDenied. Tool calls need an rmk_ key and go through ramen.v1.Mcp/Call — see the local quickstart.

Backups

POST $U/backups {"target":"bucket"} writes a JSON export tagged with the release version (zones, users without password hashes, groups, environments, workers, config; no secrets) to <bucket root>/_backups (local) or the groups bucket. Restore with POST $U/backups/{id}/restore; the bootstrap admin is re-applied from env on the next start. See the backup-restore skill.

Config yaml

RAMEN_CONFIG=/path/ramen.yaml — top-level keys map to RAMEN_* (nested keys join with _), env wins; POST $U/config/reload hot-reloads. OAuth providers, SMTP, SA rules and auth toggles live here.

Logs page

Logs