Summary
SPIRE Server always signs X.509-SVIDs with an intermediate CA that SPIRE generates and rotates itself — either self-signed, or minted as a downstream of a configured UpstreamAuthority. There is no way to sign directly with a pre-existing, long-lived intermediate that the server doesn't own.
This requests an "external CA" mode where SPIRE Server loads an operator-supplied intermediate CA (+ root), signs SVIDs directly with its key via crypto.Signer (PKCS#11 as the first backend), treats the X.509 CA as static (no rotation), and keeps JWT key rotation unchanged.
The gap
- Intermediates are commonly issued leaf-constrained (CA:TRUE, pathlen:0), forbidding any CA beneath them. SPIRE's flow requires minting a downstream sub-CA, which such a cert cannot legally sign — chains fail path validation at conforming verifiers.
- Mandatory rotation breaks non-SPIFFE consumers. SPIRE rotates its X.509 CA frequently by design. Heterogeneous systems consuming SPIRE-issued certs — with no SPIFFE-aware edge to abstract trust away — can't continuously re-fetch the bundle and refresh chains. A stable, externally-anchored CA removes that friction.
- The workaround adds CA-management burden. Provisioning a pathlen≥1 intermediate just so SPIRE can mint short-lived sub-CAs relaxes existing PKI policy and introduces a new problem: securely authorizing each spire-server to request and hold a signing-capable sub-CA. Signing directly with a fixed CA sidesteps this.
Proposed behavior
An experimental server { experimental { external_ca { … } } } block that:
- takes a root cert, an intermediate (signing) cert, and a crypto.Signer reference for the key (PKCS#11 first; design is signer-agnostic);
- validates at startup that the intermediate is signed by the root and is a CA cert (fail fast otherwise);
- uses that intermediate as the active X.509 signing authority and publishes root + intermediate in the trust bundle;
- disables X.509 CA rotation; leaves JWT rotation untouched.
Config sketch
server {
experimental {
external_ca {
enabled = true
root_cert_file_path = "/etc/spire/certs/root.pem"
cert_file_path = "/etc/spire/certs/intermediate.pem"
pkcs11 {
pkcs11_uri = "pkcs11:module-path=/usr/lib/.../libXXX.so;token=SPIRE;pin-value=…"
pkcs11_object = "pkcs11:object=intermediate-ca-key"
}
}
}
}
Scope / non-goals
- Not changing JWT-SVID behavior — JWT keys still rotate.
- Not rotating/re-issuing the external CA — its lifecycle is owned by the external PKI; SPIRE consumes it read-only.
- Not replacing UpstreamAuthority — this is "sign directly with a supplied static CA," not "mint a downstream from an upstream."
- SPIRE already supports HSM/KMS-backed signing via several UpstreamAuthority/KeyManager plugins. The novelty here is direct signing with a static, externally-owned CA.
Alternatives considered
- UpstreamAuthority (disk/vault/PKCS#11-backed): still mints and rotates a SPIRE-owned downstream; incompatible with
pathlen:0, still rotates the signing CA and doesn't scale well in heterogenous environments.
- Provision a
pathlen≥1 intermediate: relaxes PKI policy and adds sub-CA bootstrapping/management on every server.
Contribution
I have this experimental feature implemented and I will shortly link a PR to support the above which can help with the discussion.
Summary
SPIRE Server always signs X.509-SVIDs with an intermediate CA that SPIRE generates and rotates itself — either self-signed, or minted as a downstream of a configured UpstreamAuthority. There is no way to sign directly with a pre-existing, long-lived intermediate that the server doesn't own.
This requests an "external CA" mode where SPIRE Server loads an operator-supplied intermediate CA (+ root), signs SVIDs directly with its key via crypto.Signer (PKCS#11 as the first backend), treats the X.509 CA as static (no rotation), and keeps JWT key rotation unchanged.
The gap
Proposed behavior
An experimental server { experimental { external_ca { … } } } block that:
Config sketch
Scope / non-goals
Alternatives considered
pathlen:0, still rotates the signing CA and doesn't scale well in heterogenous environments.pathlen≥1intermediate: relaxes PKI policy and adds sub-CA bootstrapping/management on every server.Contribution
I have this experimental feature implemented and I will shortly link a PR to support the above which can help with the discussion.