Hanzo KMS
Key Management Service for secrets, machine-identity access, and threshold signing keys
Hanzo KMS
API reference · Hanzo KMS API → — every endpoint, generated from the OpenAPI spec.
Hanzo KMS is the key management service for the Hanzo platform. It stores secrets and API keys, hands them to workloads through short-lived machine-identity tokens, syncs them into Kubernetes, and manages threshold signing keys backed by Hanzo MPC.
| API | https://kms.hanzo.ai |
| API prefix | /v1/kms |
| Auth | Machine-identity login → bearer JWT (verified against Hanzo IAM) |
| K8s sync | KMSSecret CRD via the kms-operator |
| Source | github.com/hanzoai/kms |
Hanzo KMS exposes a single surface under /v1/kms. Secrets are addressed by org / path / name with the environment as a query parameter. There is no plaintext-secret-in-config anywhere — workloads authenticate with a machine identity and read values at runtime.
Authentication
KMS uses machine identities: a non-human clientId + clientSecret minted in Hanzo IAM. Exchange them for a short-lived access token, then send that token as a bearer on every request.
# Log in (clientId/clientSecret come from a K8s Secret or your secret store — never inline them)
ACCESS_TOKEN=$(curl -sS -X POST https://kms.hanzo.ai/v1/kms/auth/login \
-H 'Content-Type: application/json' \
-d "{\"clientId\":\"$KMS_CLIENT_ID\",\"clientSecret\":\"$KMS_CLIENT_SECRET\"}" \
| jq -r .accessToken)Response:
{ "accessToken": "<RS256 JWT>", "expiresIn": 86400, "tokenType": "Bearer" }The token is a standard JWT whose signature, issuer, and audience are validated against IAM's JWKS. Its owner claim is the organization it can act on — a token can only read secrets under its own {org}.
Secret hierarchy
A secret is addressed by four coordinates:
org / path / name ? env
hanzo / providers / OPENAI_API_KEY ? env=production- org — the organization slug; must match the token's
ownerclaim. - path — a folder within the org (e.g.
/,/providers,/db). - name — the exact secret key.
- env — a query parameter; defaults to
defaultwhen omitted.
KMS reads are exact-name — there is no "list all secrets in a folder" endpoint. Enumerate the keys your workload needs (the KMSSecret CRD does exactly this).
Reading & writing secrets
All routes are under https://kms.hanzo.ai/v1/kms/orgs/{org}/secrets.
| Method | Path | Purpose |
|---|---|---|
GET | /v1/kms/orgs/{org}/secrets/{path}/{name}?env= | Read a secret value + version |
POST | /v1/kms/orgs/{org}/secrets | Create/upsert ({path,name,env,value}) → {ok,version} |
PATCH | /v1/kms/orgs/{org}/secrets/{path}/{name} | Update (optimistic concurrency — see below) |
DELETE | /v1/kms/orgs/{org}/secrets/{path}/{name}?env= | Delete |
Read
curl -sS "https://kms.hanzo.ai/v1/kms/orgs/hanzo/secrets/providers/OPENAI_API_KEY?env=production" \
-H "Authorization: Bearer $ACCESS_TOKEN"{ "secret": { "value": "<secret value>" }, "version": 3 }A root-path secret omits the folder segment: …/secrets/STRIPE_SECRET_KEY?env=production.
Create
curl -sS -X POST "https://kms.hanzo.ai/v1/kms/orgs/hanzo/secrets" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "path": "/providers", "name": "OPENAI_API_KEY", "env": "production", "value": "<new value>" }'{ "ok": true, "version": 1 }Update (optimistic concurrency)
Updates require the current version, supplied either as an If-Match header or version in the body. A missing precondition returns 428 Precondition Required; a stale version returns 409 Conflict with the current version.
curl -sS -X PATCH "https://kms.hanzo.ai/v1/kms/orgs/hanzo/secrets/providers/OPENAI_API_KEY?env=production" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "If-Match: 3" \
-H "Content-Type: application/json" \
-d '{ "value": "<rotated value>" }'Threshold signing keys
When KMS is wired to an MPC vault, it manages distributed signing keys whose private material is never assembled in one place:
| Method | Path | Purpose |
|---|---|---|
POST | /v1/kms/keys/generate | Distributed key generation (DKG) for a validator/signing key set |
GET | /v1/kms/keys · /v1/kms/keys/{id} | List / inspect key sets |
POST | /v1/kms/keys/{id}/sign | Threshold sign (e.g. bls) |
POST | /v1/kms/keys/{id}/rotate | Reshare / rotate shares |
These operations require an admin or MPC-scoped token. See Hanzo MPC for the underlying threshold scheme.
Kubernetes integration
In a cluster, you never call the API directly — you declare a KMSSecret and the kms-operator logs in with a machine identity, reads the named keys, and writes a Kubernetes Secret you reference as normal:
apiVersion: secrets.lux.network/v1alpha1
kind: KMSSecret
metadata:
name: app-kms-sync
namespace: hanzo
spec:
hostAPI: https://kms.hanzo.ai
resyncInterval: 60
authentication:
universalAuth:
credentialsRef:
secretName: app-kms-auth # K8s Secret holding clientId/clientSecret
secretNamespace: hanzo
secretsScope:
projectSlug: hanzo # -> {org}
envSlug: production # -> ?env=production
secretsPath: /providers # -> {path}
keys: # enumerated; no list endpoint
- OPENAI_API_KEY
- ANTHROPIC_API_KEY
managedSecretReference:
secretName: app-secrets
secretNamespace: hanzo
secretType: Opaque
creationPolicy: OrphanSee the KMSSecret CRD reference for the full spec.
Next Steps
How services authenticate to KMS and refresh tokens
Complete Kubernetes sync reference
The pattern every Hanzo service uses to consume secrets
Threshold signing backend for KMS-managed keys
How is this guide?
Last updated on