HTTP API
Single listener, default :7999. All routes require mTLS except health and the PKI endpoints.
Conventions:
- Reads on the legacy secrets/certificates surface use
PATCHwith a request body (a deliberate, documented convention — the body carries scope, whichGETcannot). - Errors return
{code, message, data}. Policy denials are400with codevault-access-denied(not 403). - Tenant scope fields in bodies:
datacenter, cluster, customer, product, environment, tenant. For tenant-scoped secret operations the server ignores body scope in favor of the propagated caller CPET (see Overview).
Health (unauthenticated)
Section titled “Health (unauthenticated)”| Method | Path | Purpose |
|---|---|---|
| GET | /health | Liveness |
| GET | /ready | Readiness — 503 while the storage backend is unreachable |
| GET | /version | Build info |
Secrets
Section titled “Secrets”| Method | Path | Purpose |
|---|---|---|
| POST | /secret/:name | Save. Fields: secret, scope, startdate, enddate, indefinite |
| PATCH | /secret/:name | Read → {startdate, enddate, secret} |
| PATCH | /checksecret/:name | Exists → {secretexists}, 404 if not |
| DELETE | /secret/:name | Delete — requires the record id |
A secret key can have at most 3 active records at once (error vault-max-active-certificate-limit-reached); writing a new record supersedes the oldest.
Certificates and JWT material
Section titled “Certificates and JWT material”| Method | Path | Purpose |
|---|---|---|
| POST | /certificate/generate/internal | Issue an internal cert (RSA-4096) → {certificateserial} |
| POST / PATCH / DELETE | /certificate/internal | Save / read / revoke internal certs |
| POST / PATCH / DELETE | /certificate/external | Same for externally-issued certs |
| GET | /certificate/auth | mTLS → JWT exchange → {token} |
| GET | /certificate/internal/issuer | CA certificate PEM → {issuer} |
| PATCH | /certs/{internal,external,internaljwt,externaljwt}/list | List by type; days filter supports rotation dashboards |
| POST | /jwt/internal/generate[/:identifier] | Generate JWT signing material (per-realm via identifiername query param, default realm) |
| PATCH | /jwt/internal[/:identifier] | Read JWT signing material |
| POST / PATCH | /jwt/external/:identifier | Externally-supplied JWT material |
The private key half of JWT material is returned only to the owning service (enforced by field-level access rules).
Agent enrollment
Section titled “Agent enrollment”Used by vault-agent on each node:
| Method | Path | Purpose |
|---|---|---|
| POST | /agent/join | {secret, attributes, csr?} — consume a single-use node token → {node_spiffe_id, node_cert_chain_pem, node_key_pem, trust_bundle_pem, refresh_token, node_cert_lifetime_ns}. Node certs live 24h. Token errors map to 401 / 409 / 410 / 403 |
| POST | /agent/renew | Renew the node cert; the refresh token rotates on every renewal |
| POST | /agent/decommission | Remove the node |
Workload surface
Section titled “Workload surface”Called by vault-agent on behalf of attested local workloads. Scope is derived from the workload’s registered identity, never from the request:
| Method | Path | Purpose |
|---|---|---|
| POST | /workload/identity | Resolve the caller’s SPIFFE identity |
| POST | /workload/jwt | Mint a workload JWT — audience required; token carries rcv_aud (receiver audiences) and scope claims |
| POST | /workload/secret/{get,write,delete} | Secret ops; names use the vault: / vaultcluster: / vaultkey: prefixes; plain: is rejected |
| — | /workload/cert/* | Certificate operations proxied to the cert machinery (10 routes) |
Operator surface
Section titled “Operator surface”Requires an operator certificate. Roles are encoded in the certificate SAN as spiffe://<domain>/operator/<role>: operator-root (super-role), identity, tokens, audit, backend, signer, policy, readonly (GETs only). Role enforcement is opt-in via middleware.operator.role_enforcement.enabled (default off, logs a warning).
| Method | Path | Purpose |
|---|---|---|
| POST / GET / DELETE | /operator/node-token[/:id] | Issue / list / revoke single-use node join tokens |
| POST / GET / DELETE | /operator/identity[/*spiffe] | Register / list / revoke workload identities (SPIFFE ID + attestation selectors + tenant scope) |
| POST | /operator/audit/{query,verify} | Query and verify the audit trail (proxied to the audit service) |
| POST | /operator/root/rotate-plan|rotate-execute/:id | Root CA rotation ceremony — scaffolded, returns 501 |
| POST | /operator/backend/migrate | Backend migration — 501 |
| POST | /operator/signer/test | Signer self-test — 501 |
| POST | /operator/policy/lint | Policy lint — 501 |
CRL and OCSP (unauthenticated by design)
Section titled “CRL and OCSP (unauthenticated by design)”| Method | Path | Purpose |
|---|---|---|
| GET | /pki/crl | DER CRL (application/pkix-crl), Cache-Control: max-age=300, 24h validity |
| POST | /pki/ocsp | RFC 6960 OCSP response, 1h validity, single-serial |
Both return 503 with vault-revocation-not-configured when the revocation emitter isn’t wired. The revocation list is persisted in the storage backend and survives restarts.