KMS Integration
How Hanzo IAM stores and reads its secrets from Hanzo KMS
KMS Integration
Hanzo IAM keeps all sensitive configuration — OAuth client secrets, social-provider credentials, and admin passwords — in Hanzo KMS. Nothing sensitive is hard-coded in manifests or environment variables.
How it works
IAM authenticates to KMS with a machine identity and reads its secrets through two complementary paths:
- Direct fetch at startup — IAM logs in to KMS (
POST /v1/kms/auth/login) with its machine-identityclientId/clientSecretand reads the secrets it needs. - KMSSecret CRD — the kms-operator keeps an
iam-secretsKubernetes Secret continuously in sync as a fallback for workloads that consume secrets as env vars.
┌──────────────────────────────────────────────┐
│ Hanzo KMS (kms.hanzo.ai) │
│ org: hanzo-iam env: production │
│ machine identity: iam-service (read-only) │
└───────────────┬───────────────────┬───────────┘
direct login KMSSecret CRD
(startup) (operator sync)
│ │
▼ ▼
┌──────────────┐ ┌──────────────────┐
│ IAM pod │ │ iam-secrets (K8s) │
└──────────────┘ └──────────────────┘Machine identity
IAM uses a dedicated, least-privilege machine identity so its secrets are isolated from other services:
| Field | Value |
|---|---|
| Identity | iam-service |
| Access | read-only on the hanzo-iam org |
| Credential | clientId / clientSecret, mounted from a K8s Secret |
The credentials live in a Kubernetes Secret — only the references, never the values, are committed:
apiVersion: v1
kind: Secret
metadata:
name: iam-kms-auth
namespace: hanzo
type: Opaque
stringData:
clientId: "" # populated out-of-band from KMS/IAM, never committed
clientSecret: ""What IAM stores in KMS
IAM's secrets are organized under its hanzo-iam org in KMS:
| Category | Examples |
|---|---|
| Application client secrets | One per registered <org>-<app> application (e.g. hanzo-cloud, hanzo-chat, hanzo-platform) |
| Social provider credentials | GitHub, Google, Microsoft, Apple OAuth client IDs and secrets |
| Admin credentials | The seeded organization administrator password |
Each application's OAuth clientSecret is stored under a key named for its <org>-<app> slug — never inlined into init_data.json or a manifest.
Syncing IAM's secrets to Kubernetes
apiVersion: secrets.lux.network/v1alpha1
kind: KMSSecret
metadata:
name: iam-kms-sync
namespace: hanzo
spec:
hostAPI: https://kms.hanzo.ai
resyncInterval: 60
authentication:
universalAuth:
credentialsRef:
secretName: iam-kms-auth
secretNamespace: hanzo
secretsScope:
projectSlug: hanzo-iam # IAM's own org
envSlug: production
secretsPath: /
keys:
- IAM_ADMIN_PASSWORD
- HANZO_CLOUD_CLIENT_SECRET
- GITHUB_CLIENT_SECRET
managedSecretReference:
secretName: iam-secrets
secretNamespace: hanzo
secretType: Opaque
creationPolicy: OrphanHow other services consume an IAM secret
A service that authenticates via IAM OIDC stores its own client_secret in KMS and syncs it the same way. For example, an app reads its OIDC client secret from a synced Secret:
env:
- name: OIDC_CLIENT_SECRET
valueFrom:
secretKeyRef:
name: app-secrets
key: OIDC_CLIENT_SECRETSee KMS Service Integration for the full pattern.
Security model
- No plaintext secrets in git — Kubernetes Secrets are populated from KMS, never committed.
- Least privilege — IAM's machine identity is read-only and scoped to its own org.
- Isolation — IAM's secrets live in a separate KMS org from service secrets.
- Audit trail — every read and write is logged in KMS.
Next Steps
Hanzo KMS architecture and the secret API
How every Hanzo service consumes secrets from KMS
Service-to-KMS authentication
How is this guide?
Last updated on