Skip to content

FR: Sign X.509-SVIDs with a static, externally-anchored CA (no SPIRE-minted downstream intermediate) #7018

Description

@calderonth

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

  1. 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.
  2. 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.
  3. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions