CDS HTTP API
Every endpoint the Certificate Distribution Service serves — attestation and certificate issuance, CA handoff, the image allowlist CRUD surface, and the discovery routes — with method, path, authorization, and response codes.
The CDS (Certificate Distribution Service) serves one HTTP API over
RA-TLS on port 8443. Every
flag that configures it is in the CLI reference.
Attestation and issuance
| Method | Path | Auth | Purpose |
|---|---|---|---|
POST | /authenticate | none | issue a one-time challenge nonce (--challenge-ttl, default 60s) |
POST | /attest | challenge + evidence | verify evidence (and an optional sandbox token) and sign a CSR, returning the leaf PEM chain |
POST | /attest-key | challenge + evidence | verify evidence and issue an EAR bound to the caller's key |
POST | /sign-csr | EAR | sign a CSR for a caller that already holds an EAR bound to the CSR key |
POST | /handoff | EAR | hand the mesh CA and allowlist snapshot to an attested peer replica; mounted only with --handoff-measurements |
Allowlist
| Method | Path | Auth | Purpose |
|---|---|---|---|
GET | /allowlist | none | the whole document as canonical JSON; returns a weak ETag W/"<version>" and honors If-None-Match (304 when unchanged) |
PUT | /allowlist | operator token | replace floor and workloads atomically; the CDS assigns the new version; 204 |
POST | /allowlist/digests | operator token | add one floor entry { digest, image }; 204 |
DELETE | /allowlist/digests | operator token | delete { digests: [...] } atomically — all-or-nothing, 404 if any is missing |
PUT | /allowlist/workloads/<name> | operator token | create or replace one workload entry, whole; 204 |
DELETE | /allowlist/workloads/<name> | operator token | delete one workload entry; 404 if absent |
A missing or invalid operator token is 401; a body the CDS cannot parse or validate is 422.
Writes carry their own 1 MiB body cap, independent of the --max-request-size that bounds the
attestation endpoints.
Enforcers poll GET /allowlist and use the ETag to avoid redundant work — the version only
changes when the set actually changes (nriImagePolicy.refresh.interval, default 30s).
Secrets
| Method | Path | Auth | Purpose |
|---|---|---|---|
GET | /secrets/<path> | mesh leaf + sandbox token | read a released value; 404 when the path is ungranted or absent |
POST | /secrets/<path> | mesh leaf + sandbox token | mint and store 32 random bytes at an empty path; 409 when another caller won the race |
PUT | /secrets/<path> | operator token | store an operator-supplied value; create-only unless the caller asked to overwrite |
Denials are deliberately opaque — an ungranted path is indistinguishable from a missing one, so the API cannot enumerate the store. The reason goes to the CDS log. Workload routes are rate-limited per sandbox, keyed on the ID in the verified client certificate.
The CDS declines to serve /secrets at all when --ratls-platform, --measurements, or
--sandbox-inventory-cidr is missing, or when CA handoff is configured. See
Application secrets.
Discovery
| Method | Path | Auth | Purpose |
|---|---|---|---|
GET | /operator-keys | none | the pinned operator public-key PEM bundle; 404 when allowlist writes are disabled |
GET | /.well-known/jwks.json | none | the EAR-signing JWKS (ES256) |
GET | /ca | none | the mesh CA bundle |
GET | /readyz | none | readiness; fails if the attestation-api is unhealthy, or CA validity is below --min-ca-validity |
Operator tokens
Every allowlist and operator-supplied secret write carries a JWT signed with the operator's ECDSA key (ES256, ES384, or ES512, matching the key's curve), minted fresh per request with a 60-second lifetime. Three claims bind it to that one write:
| Claim | Binds |
|---|---|
pbh | SHA-256 of the exact request body |
htm | the HTTP method |
htu | the URL path |
The CDS accepts a mutation only when the signature verifies against a pinned key, exp − iat is
at most five minutes (a server-side cap), the method and path match the request being
handled, and the body hash matches a re-hash of the body actually received, compared in constant
time. See Authorizing mutations for
the trust boundaries of this design, and
Manage the allowlist for the CLI that mints them.