Skip to main content
RunBook Academy

Secrets, PKI & CertificatesIV · PKI FoundationsPKI

Designing an intermediate CA layout for blast-radius control

Intermediate⏱ ~24 min🧪 Lab requiredopenssl

What you'll learn

  • Choose the number of issuing CAs from what you need to discard independently
  • Encode a separation decision as basicConstraints, extendedKeyUsage and nameConstraints
  • Predict what a compromise of one issuing CA does and does not affect
  • Plan issuing CA validity so that no leaf outlives its issuer

Prerequisites

Practice

Verified against OpenSSL 3.5.x teaching target; 3.0+ minimum · OpenSSH 10.x teaching target; 8.2+ minimum for certificate workflows · OpenBao 2.6.x · Smallstep step-ca 0.30.x · Certbot / Pebble Certbot current release; Pebble 2.10.x ACME test server · Kubernetes (cross-course target) 1.36.x · PostgreSQL 17.x · 2026-08-26

Not yet marked complete on this device.

Once a root exists, every remaining design decision is about the layer beneath it, because that is the layer you can still change. The question is usually posed as how many intermediates to create. Asked that way it has no answer. Asked as what do I want to be able to throw away independently, it answers itself.

The issuing CA is the unit of blast radius

If a signing key is compromised, every certificate that key could have issued must be treated as suspect, whether or not you can show it was issued. You cannot partially distrust an issuing CA. There is no mechanism that says trust the certificates it signed before Tuesday, because the attacker holding the key can backdate.

So the practical consequence of a compromise is: revoke the issuing CA certificate, stand up a replacement under the same root, and reissue every leaf beneath it. The size of that job is set entirely by how you drew the boundaries. One issuing CA for the whole estate means the incident is estate-wide. Four issuing CAs mean the incident is confined to a quarter of it, provided the four really are separate.

That proviso is the part teams skip. Four CA certificates whose private keys sit on the same host, under the same service account, reachable by the same automation token, are one CA wearing four hats. The separation has to exist in key storage and access control, not only in the certificate profile.

Four axes worth separating on

Not every axis is worth a CA. Each one you add is another key to protect, another expiry to track and another CRL to publish. Pick the ones where an independent failure is genuinely plausible.

  • Purpose. Server authentication, client authentication and device identity have different issuance policies, different lifetimes and different requesters. Separating them means a flaw in the client enrolment path cannot mint a server identity.
  • Environment. A staging CA lets you run a permissive policy where experimentation belongs, without that permissiveness being one configuration mistake away from production. It also gives you a realistic place to rehearse a CA rotation.
  • Operational owner. If the network team issues device certificates and the platform team issues service certificates, giving each its own CA means neither can accidentally issue in the other’s namespace and each can be audited on its own.
  • Automation class. Short-lived certificates issued automatically many times a day and long-lived certificates issued manually have opposite risk profiles. Splitting them lets the automated CA hold a key that is online by design while the manual one does not.
flowchart TD
    R["Root CA\npathlen:1, offline"] --> S["Server CA\npathlen:0, serverAuth"]
    R --> C["Client CA\npathlen:0, clientAuth"]
    R --> D["Device CA\npathlen:0, name-constrained"]
    S --> S1["api.internal.example.com"]
    C --> C1["service account identities"]
    D --> D1["fleet device identities"]

Each branch in that hierarchy is an independent unit of failure. A compromise of the device CA costs the fleet certificates and nothing else; the server CA and the client CA continue operating, and the root is never touched. That is the only property the layout is buying, and it is worth being explicit that it buys nothing else.

Making the diagram enforceable

A drawing is not a control. Three extensions turn a separation decision into something a conforming verifier applies whether or not your operators cooperate.

# device-issuing CA, signed by the root
basicConstraints=critical,CA:TRUE,pathlen:0
keyUsage=critical,keyCertSign,cRLSign
extendedKeyUsage=clientAuth
nameConstraints=critical,permitted;DNS:.device.internal.example.com
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always

pathlen:0 stops this CA creating another CA beneath itself, so the tree cannot grow sideways without a root operation. The extended key usage on the CA constrains what its leaves may be used for, because a verifier intersects the usages down the path. nameConstraints is the strongest of the three: with a permitted subtree of .device.internal.example.com, a certificate this CA issues for api.example.com will be rejected by a verifier that processes the extension, even though the signature is perfectly valid.

OpenSSL writes these constraints as a name beginning with permitted or excluded followed by a semicolon, then a name form and value that otherwise follows the subjectAltName syntax. Marking the extension critical is deliberate: a verifier that does not understand a critical extension must reject the certificate outright, which converts an unsupported constraint into a visible failure rather than a silent bypass.

Read the extensions back off the issued CA certificate rather than trusting that the configuration file was the one used. A signing command that was pointed at the wrong extension file produces a perfectly valid certificate with none of your constraints in it, and nothing downstream will complain:

CA_CERT=device-ca.crt
openssl x509 -in "$CA_CERT" -noout \
  -ext basicConstraints,keyUsage,extendedKeyUsage,nameConstraints

Confirm four things in that output: CA:TRUE with the intended pathlen, keyCertSign present in the key usage, the extended key usage you expected, and the permitted subtree spelled exactly as designed. An extension that is simply absent from the output was never applied, and absence is the failure mode to look for, because a missing constraint imposes no limit at all.

A worked layout and the decisions behind it

Here is a three-CA layout under a single offline root, with the reason each row exists rather than just its settings.

Issuing CAConstraintWhy it is separateWhat its loss costs
Server CApathlen:0, serverAuthHighest issuance volume, fully automatedReissue every service certificate
Client CApathlen:0, clientAuthDifferent enrolment path and requestersReissue workload identities; services keep serving
Device CApathlen:0, name-constrainedSlow renewal cycle, physically dispersedField visit or remote enrolment campaign

The root above them carries pathlen:1, which permits exactly one intermediate between it and any leaf. That single value is what stops any of the three quietly acquiring the ability to create a fourth.

Notice that the rightmost column is the actual design output. If two rows would produce the same recovery action at the same cost, they do not need to be separate CAs and you have added key management overhead for nothing.

Validity arithmetic that decides whether the layout survives

Path validation requires that the validity period of every certificate in the path includes the current time. Every certificate, not just the leaf. A leaf whose notAfter runs past its issuing CA’s notAfter is therefore not valid for its whole nominal life; it stops validating on the day the CA expires, and it does so for every client at once.

That gives a hard rule and a soft one. The hard rule is that an issuing CA must remain valid at least as long as the longest-lived certificate it will issue. The soft rule is that it should remain valid considerably longer, because you want a comfortable window in which the replacement CA is already trusted and issuing before the old one lapses.

Rotating an issuing CA is cheap only in principle. The new intermediate has to reach every server’s chain file, and every server has to reload so that the running process actually serves it. Neither of those is a PKI operation, which is why intermediate rotations tend to fail in the deployment pipeline rather than in the CA. Plan the rotation as a deployment with a verification step, and confirm from an external client that the chain being presented is the new one.

Production discipline

  1. Justify every issuing CA by its recovery action. If two CAs would be recovered the same way at the same cost, merge them.
  2. Separate the keys, not just the certificates. Different storage, different credentials, different automation identity, or the separation is cosmetic.
  3. Set pathlen:0 on every issuing CA and pathlen:1 on the root. Omitting the field imposes no limit, which is almost never intended.
  4. Check that no leaf lifetime can exceed its issuer’s remaining validity. Enforce it in the issuance path, not in a wiki page.
  5. Rehearse an intermediate rotation in the staging hierarchy. The step that fails is usually the reload, and you want to find that out where nobody is watching.

Cross-course references

  • Linux for Production Sysadmins - Part LXXII (Secrets) covers separating credential storage per service account, which is what makes the key separation in this layout real rather than nominal.
  • Kubernetes for Production Sysadmins - Part CI (ClusterBoundaries) covers deciding where an isolation boundary belongs, the same reasoning applied to clusters instead of certificate authorities.
  • Git, CI/CD & GitOps for Infrastructure Engineers - Part XCI (LeastPrivilege) covers scoping automation credentials so that one pipeline cannot invoke every signer it can reach.

Quiz

Knowledge check · 4 questions

  1. Q1. Three issuing CA certificates exist, but all three private keys sit on one host under one service account. What has the layout achieved?

  2. Q2. A leaf certificate remains valid for its full stated lifetime even if its issuing CA certificate expires first.

  3. Q3. Name three extensions that constrain what an issuing CA may do, and state what each one restricts.

  4. Q4. Scope the incident and set out the recovery, given this layout.

    At 02:40 UTC an alert shows an unexpected certificate issued for api.internal.example.com. The estate runs one offline root with three issuing CAs: server, client and device. The signature on the unexpected certificate traces to the client CA, which is name-constrained to .clients.internal.example.com and carries clientAuth only. The server CA shows no unexplained issuance.

Passing score: 75%. Answers are checked in this browser.