Cluster PKI posture — per-node trust state plus the cluster rollup.
curl --request GET \ --url https://stratum.example.com/v1/admin/pki/cluster-ca \ --header 'Authorization: Bearer <token>'Answers “does this cluster agree on one CA, and is anything
silently wrong with it?” from one place, instead of SSHing to every node to
run openssl x509 -noout -fingerprint -sha256 and bao kv get.
PKI failures here are invisible by default. On the 2026-08-03 from-zero
rebuild the install reported success while /etc/stratum/pki was empty, the
front door served its self-signed bootstrap certificate and node mTLS was
off — nothing failed, and it was found only by grepping the control-plane
log. On 2026-08-02 the cluster ran with three different roots sharing one
subject. Both states are a healthy: false here.
Each node self-reports its own row; a node that stops reporting reads as
stale/unknown rather than as agreement. Install-scope; gates on
pki:DescribeClusterCA.
Returns certificate metadata only. Fingerprints, subjects and validity windows — never key material. There is deliberately no rotate action: republishing the cluster CA silently invalidates every certificate issued under the previous one, so rotation is a runbook with a staged re-issue plan, not an API call.
Authorizations
Section titled “Authorizations”Responses
Section titled “Responses”The cluster’s PKI posture.
The cluster’s internal PKI posture: what each node trusts, which rung of the CA-resolution ladder it took, and whether the cluster agrees with itself. Read-only. Never carries private key material — the issuing key stays in OpenBao (secret/stratum/pki/cluster-ca).
object
True only when every reporting node agrees on one CA, none reports an orphan local CA, a lingering issuing key or a refused resolution, no node has gone stale, and the front door (if seeded) is issued by the cluster CA. This is the single verdict the Admin PKI page and stratumctl admin selfcheck key off.
Whether every fresh, reporting node presents the same trust-bundle fingerprint. Zero reporting nodes is NOT consistent — nothing has been established.
The SHA-256 fingerprint the cluster agrees on, as colon-separated uppercase hex (identical to openssl x509 -noout -fingerprint -sha256). Empty when nodes disagree — there is no single answer to give.
Subject of the agreed CA, e.g. O=Stratum,CN=Stratum Cluster Root CA cl-3lcb6xjf.
Days until the agreed CA expires; null when no agreed CA has a known validity window. The root is long-lived (a decade), which is exactly why nothing noticed it before this endpoint existed.
Every distinct trust-bundle fingerprint across fresh nodes. Length > 1 is the divergence state — certificates issued under one will not verify under the others.
Nodes whose last report is too old to believe. Their trust state is UNKNOWN, which the rollup deliberately does not treat as agreement.
One node’s view of the cluster PKI, self-reported by that node’s own control plane (platform.pki_node_status). Certificate metadata only — no key material.
object
SHA-256 of the trust bundle at /etc/stratum/pki/cluster-ca.crt — what this node actually verifies peers and the front door against. Colon- separated uppercase hex. Empty when the file is absent.
Every root in this node’s /etc/stratum/pki/cluster-ca.crt, sorted. Normally one. More than one during a CA rotation overlap, where each node must trust both the outgoing and incoming roots before signing cuts over. caFingerprint is whichever of these the node agrees the cluster currently signs with.
This is a FILE. It is not evidence that any process on the node has read it — see reloadedCaFingerprints, which is what the CA rotation barrier gates on.
The roots this node’s CA consumers were actually driven onto, sorted. Distinct from trustedCaFingerprints on purpose: a root present in the file changes nothing until the daemon holding an older copy re-reads it, and the CA rotation barrier gates on THIS field for that reason.
Empty means no refresh has been recorded on this node, which the barrier treats as blocking rather than as agreement — the expected state on a node whose host-helper has not yet been upgraded, and the usual answer to “why is my rotation stuck at distributing when every node already trusts the incoming root”.
Three consumers are covered, and this reports their INTERSECTION, so a root any one of them is missing does not clear the barrier: postgres-ha, driven by the node’s host-helper; the control plane’s own mTLS verifier; and the control plane’s database pool. The last two report themselves because nothing outside that process can observe them. Three quadlets that also mount the bundle — axdnsd, axlbd-stratum-front, postgres-exporter — are not yet assessed.
This covers what each consumer TRUSTS, never what it PRESENTS. A node can report every root here and still be unable to connect, if the leaf it offers was signed by a root its peer has retired. A full reloadedCaFingerprints is therefore not on its own evidence that a rotation left the fleet healthy.
The CA this node’s control plane resolved as authoritative (normally read from OpenBao). Empty when resolution refused. Differs from caFingerprint only when the node trusts something the cluster does not issue from.
Which rung of the pki.ResolveClusterCA ladder this node took. Empty means REFUSED — the node is not entitled to mint and none was published, so it can issue neither join bundles nor a front-door certificate. On a healthy cluster the founder reads adopted and joiners read store.
This node held a local CA disagreeing with the distributed trust bundle — a root minted by the pre- control plane. Inert now, but it proves the node once could have issued certificates the cluster would reject.
A surviving /var/lib/stratum/pki/cluster-ca.key. Post- the key is dropped once the CA is published, so presence means the node regressed or is running an old binary.
Whether this node has its own transport leaf at /etc/stratum/pki/node.crt. Absent on an HA node means cross-node console/session relay and node mTLS are DISABLED there.
The trusted root whose signature verifies this node’s leaf. Determined by signature, not by issuer name — produced several roots sharing a single subject, so a name identifies nothing. Empty when the leaf is absent, or when no trusted root signed it, which means the node holds a leaf it cannot chain. Drives the CA-rotation re-issue barrier: without it a re-issued leaf is indistinguishable from the original.
CaFingerprint differs from resolvedCaFingerprint. False when either is unknown — that is “cannot tell”, not divergence.
This node alone is free of findings.
When this node last reported, stamped server-side. A timestamp older than the staleness window makes the node UNKNOWN rather than agreeing.
The substrate front door’s serving certificate (lb.ssl_certificates). Its issuer is the difference between an endpoint clients can verify against /etc/stratum/pki/cluster-ca.crt and the unverifiable bootstrap certificate the 2026-08-03 rebuild silently shipped.
object
Whether a front-door certificate row exists yet. False on a fresh install where the LB seeder has not run — deliberately distinct from a row that exists and is self-signed, which is a finding.
Recorded issuer of the front-door certificate.
The root that actually SIGNED the front-door certificate. issuer above is a class and stays cluster-ca across a CA rotation, so it cannot tell a current root from a retired one — and after a rotation the two share a subject, so names cannot either. When this differs from the cluster’s agreed CA the front door is unverifiable, which is exactly what a completed rotation leaves behind.
True only for cluster-ca. When false and present, clients cannot verify the front door against the cluster CA.
SNI match set, e.g. private.stratum-labs.cloud, *.private.stratum-labs.cloud.
Operator-readable statements of what is BROKEN, empty when healthy. Each names the affected node and the remediation rather than just the condition, because these are the strings selfcheck prints on failure. healthy is false exactly when this list is non-empty.
Statements of what is DEGRADING but still working — a node transport leaf that automatic renewal has not refreshed, or a cluster root approaching expiry. Deliberately separate from findings: these do not clear healthy and must not fail a deploy gate, because they describe something with weeks or months of runway. stratumctl admin selfcheck renders them as WARN.
Example
{ "nodes": [ { "resolutionSource": "" } ], "frontDoor": { "issuer": "manual" }}Authenticated but not authorized.
object
The findings of a rejected IAM policy document (custom and resource policies).
One finding of a rejected IAM policy document. A rejection lists every finding, so the author fixes the document in one round trip.
object
The finding, e.g. INVALID_DOCUMENT, UNKNOWN_ACTION, ACTION_NOT_APPLICABLE.
Index of the statement at fault; -1 for the document as a whole.
The offending action, where one is at fault (ACTION_NOT_APPLICABLE).
Field errors, for codes that carry them: each problem at its field
(see FieldError). Documented on the responses that set it, e.g.
approveNodeJoin’s INVALID_INPUT and JOIN_APPROVAL_REFUSED.
Absent otherwise.
One field’s problem, the stage-2 installer API’s shape.
field is the field’s path, message what is wrong with it.
object
The field’s path, e.g. links[0].interface, disks[1].confirm,
mgmt.address or role; empty for the whole request.
Structured facts about the refusal, for codes that carry them. The
shape is fixed per code and documented on the response that answers
it, e.g. IMAGE_POOL_MISMATCH (see ImagePoolMismatchDetails) and
IMAGE_IN_USE. Absent for codes that carry none.
object
Example
{ "issues": [ { "code": "ACTION_NOT_APPLICABLE", "action": "compute:CreateVpc" } ]}