Skip to content

Issuer key custody: Supabase Vault with a KeySigner seam, transit KMS reserved

Status: accepted

ADR-0015 said issuer keys live “in a KMS”, but no KMS exists in the stack — while supabase_vault is already deployed, live, and operated (CNPG ImageVolume extension image, infra/utils/cloudnativepg/supabase/). The OB 3.0 / VC-DM 2.0 specs themselves mandate nothing about key storage; the only requirement is valid Ed25519 JWS (ADR-0016) plus JWKS discovery.

  • Ed25519 issuer private keys are stored in Supabase Vault (encrypted at rest, root key held outside the database). This satisfies ADR-0015’s intent — platform custody, organizations never hold keys, rotation policy, JWKS endpoints — with one recorded deviation: Vault has no signing API, so the private key enters apps/api memory at sign time.
  • Guardrails:
    1. Issuer keys live in a dedicated vault scope readable only by a dedicated signing DB role — never the general application role.
    2. All signing goes through a KeySigner seam in apps/api; the custody mechanism is an implementation detail behind it.
    3. Every sign operation is recorded in an application-level audit log.
    4. Upgrade trigger: when credential revocation/status infrastructure lands or multi-org production issuance begins, custody moves to a transit-style KMS (OpenBao) behind the same seam — additive via JWKS kid rotation, never a re-issuance event.
  • OpenBao transit now. Keys would never leave the KMS and per-sign audit is built in, but it adds a stateful service (unseal, backup, HA) before the first credential exists. With revocation deferred, an apps/api compromise allows minting credentials under either design; transit’s marginal win — no offline key exfiltration, so rotation fully remediates — is real but does not justify the operational cost yet. It remains the named upgrade path.
  • pgsodium server-side signing. Would keep keys out of app memory, but pgsodium is deprecated upstream; not a foundation.
  • The deviation from ADR-0015’s literal “KMS” wording is this ADR; ADR-0015’s custody intent is unchanged.
  • Key generation, vault scope provisioning, the signing DB role, and the JWKS table land together as the first credential-lane slice.