Four failures, both causes the same shape: state that belongs to the whole process being read or written as if it belonged to one test. TestEnvRequired_* (x3) failed with 401 on requests whose tokens were fine. Embed applies ExpectedIssuer/ExpectedAudience/JWKSURL to the process-global authConfig — that is what Embed is FOR — and stopping the instance does not put it back. So after TestEmbed the process no longer accepted sharedIssuer, and verification reached for a JWKS server TestEmbed had already closed. Every later test minting a shared-issuer token got 401, and the only reason it was those three is that they sort after TestEmbed. They passed in isolation, which is what made it look like their problem. jwtTestEnv.cleanup already restores exactly this; the embedded path had been missed. Registered before jwks.Close so it runs last (t.Cleanup is LIFO). TestConnMemory measured runtime.NumGoroutine() — process-wide — and divided it by the connections under test. Run alone that ratio is 1.00; run inside the package it also counts badger compactors, httptest servers and whatever else is still up, and it read 1.15 against a [0.95, 1.05] band. The test was failing for goroutines it does not own. It now takes a goroutine baseline and reports the delta, which is what the heap half of the same function has always done two lines above. Package green, twice. Co-authored-by: Hanzo Dev <[email protected]>
Hanzo KMS
Secrets, keys, and threshold signing for the Hanzo platform — per-org namespaces, IAM-gated, ZAP-native, MPC-backed. A thin Go server over the canonical luxfi/kms primitives.
What this is
Hanzo KMS is the canonical secret store and signing service for every Hanzo deployment. It holds the per-tenant DEKs that back Hanzo Base, the provider API keys the AI and gateway services consume, certificate material, and validator signing keys.
AI agents are first-class identities: every secret carries a policy that controls whether an agent may read it — auto-approve, requires-approval, or blocked — with a full per-agent audit trail.
All server logic lives in luxfi/kms. This module wires those primitives with Hanzo defaults (IAM at hanzo.id, encrypted-at-rest storage, S3 replication) and adds JWT verification, the audit ledger, version CAS, and header hygiene. It mounts into the unified cloud binary (kms.Mount) and also ships as a standalone daemon.
Quick start
Build from source — pure Go, no database toolchain required:
make kmsd kms # builds ./kmsd (daemon) and ./kms (admin CLI)
KMS_ENV=dev ./kmsd # HTTP on :8443, ZAP on :9999
Or run the container image (pin a released tag — never :latest):
docker run -p 8443:8443 ghcr.io/hanzoai/kms:vX.Y.Z
In any non-dev environment the daemon refuses to boot without full JWT config (KMS_EXPECTED_ISSUER, KMS_EXPECTED_AUDIENCE, KMS_JWKS_URL) — fail-closed by design.
AI access control
Your secrets, your rules. AI agents are first-class citizens — and so is your ability to block them.
- Per-secret policies — mark any secret
requires-approval; a read from any agent triggers a real-time approval prompt. - Auto-approve mode — move fast in development, escalate specific secrets to manual sign-off before production.
- Identity tracking — see exactly which model, tool, or agent accessed which secret, and when.
- Full audit trail — every AI-originated read is logged with agent identity, timestamp, and reason.
Secret: STRIPE_LIVE_KEY
policy: requires-approval
reader: agent via hanzo-mcp
status: waiting for approval → [approve] [deny]
API surface
Everything is served under /v1/kms — one canonical path per operation, no aliases, no /api/. Every endpoint requires a Hanzo IAM JWT (RS/ES/PS/EdDSA — never HS*, never none) or an explicit admin role.
| Group | Endpoints |
|---|---|
| Auth | POST /v1/kms/auth/login — machine-identity client credentials → IAM token |
| Secrets (per-org) | GET / POST / PATCH / DELETE /v1/kms/orgs/{org}/secrets/… — env is a first-class key component; writes require an explicit env; PATCH requires version CAS via If-Match |
| MPC keys | POST /v1/kms/keys/generate · /{id}/sign · /{id}/rotate · GET /v1/kms/keys · /v1/kms/status — threshold BLS / round signing via luxfi/mpc |
| Health | GET /healthz — liveness, no auth |
A sub-100µs binary ZAP transport (default :9999) mirrors the HTTP surface for in-cluster callers under the identical JWT + role model. The Go client at sdk/go (HTTP with ZAP fallback) is what every other Hanzo service uses to fetch secrets at runtime.
Storage & durability
- At rest — ZapDB (LSM) at
$KMS_DATA_DIR; per-secret 256-bit DEK wrapped under the master key (AES-256-GCM). - Replication — age-encrypted incremental + snapshot backups streamed to S3 (off when unset).
- Audit — buffered SQLite side-table; single writer, never blocks the request path.
Specs
- HIP-0027 — KMS
- HIP-0106 — Unified Cloud Binary (kms subsystem)
- HIP-0302 — Encrypted SQLite + ZapDB durability (DEK source)
Security
Please do not open public GitHub issues for security vulnerabilities. Email [email protected] with a description and, ideally, a reproduction. We respond quickly.
License
MIT — see LICENSE. Portions are derived from Infisical (MIT, © 2022 Infisical Inc.); see NOTICE. The current request path is a thin wrapper over luxfi/kms; no original upstream server code remains on the wire.
Hanzo — the Open AI Cloud
Open source · every language · on-chain settlement. hanzo.ai · docs.hanzo.ai
SDKs in every language — Python (flagship) · TypeScript · Go · Rust · C++ · Swift · Kotlin · umbrella