zeekayandHanzo Dev fce2fe8f73 kms: root-level secrets were unfetchable — GET/DELETE now split path optionally
The store keys on (path, name) and accepts an empty path, so List and POST have
always handled secrets at the root of an org. GET and DELETE split `{rest...}` on
the last "/" and returned 400 "path and name required" when there wasn't one —
so every root-level secret was permanently unreachable while List cheerfully
advertised it. Against the same deployed v1.12.9:

  GET /v1/kms/orgs/bootnode/secrets?path=&env=prod
    -> 200 {"names":["DATABASE_URL","API_KEY","APP_SECRET", ...]}
  GET /v1/kms/orgs/bootnode/secrets/DATABASE_URL?env=prod
    -> 400 {"message":"path and name required"}

Two routes over one store disagreeing about what is addressable.

This is why KMS→k8s secret sync has been 100% dead since 2026-03-17 (54/54
KMSSecret CRs failing on lux-k8s). The bootnode org stores its secrets flat, so
the kms-operator could enumerate them and never fetch one. Auth, org scoping and
the operator's native /v1/kms client were all fine — the fetch could not
express "a secret at the root".

Split on the last "/" when there is one; otherwise the whole rest is the name.
An empty name still 400s (now "name required", which is what it means). DELETE
carried the identical split so it gets the identical guarantee.

TestSecretRoutes_RootLevelSecretIsAddressable pins the round trip: list sees it,
get fetches it, delete removes it, 404 after. Verified red/green — without the
handler change it fails with the exact production error.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-26 08:39:09 -07:00
2026-07-26 01:14:27 -07:00
2026-06-28 20:36:07 -07:00

kms

KMS

MPC-backed key management service for the Lux Network. Manages validator keys, threshold signing, and key rotation using distributed MPC (Multi-Party Computation).

No legacy fork. No PostgreSQL. Pure Go server backed by MPC for threshold cryptography and a JSON file store for metadata.

Architecture

┌─────────────┐      ┌─────────────┐      ┌─────────────┐
│   Client     │─────▶│   KMS   │─────▶│   MPC   │
│ (ATS / BD)   │ HTTP │  Go Server  │ HTTP │  CGGMP21 /  │
│              │      │  :8080      │      │  FROST      │
└─────────────┘      └──────┬──────┘      └─────────────┘
                            │
                     ┌──────▼──────┐
                     │  JSON Store │
                     │  keys.json  │
                     └─────────────┘

How it works

  1. KMS is the HTTP API layer — manages validator key lifecycle
  2. MPC is the crypto backend — performs distributed key generation (DKG) and threshold signing
  3. Store is a JSON file — maps validator IDs to MPC wallet IDs (no database needed)

Key types

Key Protocol Curve Use
BLS CGGMP21 secp256k1 Consensus signing (BLS aggregation)
Corona FROST ed25519 Ring signatures, post-quantum prep

Integration with Hanzo Base

KMS runs as a standalone service alongside Hanzo Base services (ATS, BD, TA). In production:

                    ┌──────────────────────┐
                    │     hanzoai/gateway   │
                    └──────────┬───────────┘
                               │
          ┌────────────────────┼────────────────────┐
          │                    │                    │
    ┌─────▼─────┐       ┌─────▼─────┐       ┌─────▼─────┐
    │    ATS     │       │    BD     │       │    TA     │
    │  (Base)    │       │  (Base)   │       │  (Base)   │
    │  :8090     │       │  :8091    │       │  :8092    │
    └─────┬─────┘       └─────┬─────┘       └─────┬─────┘
          │                    │                    │
          └────────────────────┼────────────────────┘
                               │
                         ┌─────▼─────┐       ┌───────────┐
                         │  KMS  │──────▶│  MPC  │
                         │  :8080    │       │  :8081    │
                         └───────────┘       └───────────┘

Base services call KMS for:

  • Transit encrypt/decrypt — field-level encryption with per-customer DEKs
  • Validator key management — generate, sign, rotate validator keys
  • MPC signing — threshold signing for cross-chain bridge operations

IAM Integration

KMS authenticates callers via Hanzo IAM JWT tokens. The Authorization: Bearer <token> header is validated against the IAM JWKS endpoint. No API keys, no separate auth system.

API

POST   /api/v1/keys/generate      Generate validator key set (BLS + Corona via MPC DKG)
GET    /api/v1/keys                List all validator key sets
GET    /api/v1/keys/{id}           Get validator key set by ID
POST   /api/v1/keys/{id}/sign     Sign message with BLS or Corona key
POST   /api/v1/keys/{id}/rotate   Rotate (reshare) keys with new threshold/participants
GET    /api/v1/status              KMS + MPC cluster status
GET    /healthz                    Health check

Generate keys

curl -X POST http://kms:8080/api/v1/keys/generate \
  -H 'Content-Type: application/json' \
  -d '{"validator_id": "node-0", "threshold": 3, "parties": 5}'

Sign with BLS

curl -X POST http://kms:8080/api/v1/keys/node-0/sign \
  -H 'Content-Type: application/json' \
  -d '{"key_type": "bls", "message": "base64-encoded-message"}'

Configuration

Env Var Flag Default Description
KMS_LISTEN --listen :8080 HTTP listen address
MPC_URL --mpc-url http://mpc-api.lux-mpc.svc.cluster.local:8081 MPC daemon URL
MPC_TOKEN --mpc-token - MPC API auth token
MPC_VAULT_ID --vault-id - MPC vault ID (required)
KMS_STORE_PATH --store /data/kms/keys.json Key metadata store path

Running

# Build
go build -o kms ./cmd/kms

# Run (requires MPC daemon running)
./kms --vault-id=<your-vault-id> --mpc-url=http://localhost:8081

Kubernetes

KMS deploys as a Deployment (not StatefulSet — metadata is on a PVC or ConfigMap):

apiVersion: apps/v1
kind: Deployment
metadata:
  name: kms
spec:
  replicas: 2
  template:
    spec:
      containers:
      - name: kms
        image: us-docker.pkg.dev/<project>/backend/kms:main
        ports:
        - containerPort: 8080
        env:
        - name: MPC_VAULT_ID
          valueFrom:
            secretKeyRef:
              name: kms-secrets
              key: MPC_VAULT_ID

K8s Operator

The k8-operator/ directory contains a Kubernetes operator that syncs KMS-managed secrets into K8s Secret resources. CRDs:

  • KmsSecret — pull secrets from KMS into K8s Secrets
  • KmsDynamicSecret — ephemeral secrets with TTL
  • KmsPushSecret — push K8s Secrets to KMS
  • luxfi/mpc — MPC daemon (CGGMP21 + FROST)
  • luxfi/hsm — Hardware Security Module abstraction
  • hanzoai/base — Go application framework (ATS, BD, TA use this)
  • hanzoai/iam — Identity and Access Management

License

MIT — see LICENSE

S
Description
Lux KMS is an open-source platform for secure credentials management.
Readme
1.1 GiB
Languages
Go 99.5%
Dockerfile 0.4%