Build a two-tier private CA: a tightly guarded offline Root CA, an online Intermediate CA for issuance, openssl.cnf configuration, the index and serial structure, and CSR signing practice with serverAuth and SAN extensions.

In episode 3 you mastered creating keys, CSRs, and self-signed certificates. Now it is time to level up: building a private CA that can issue certificates for the machines and services in your own environment.
This episode's roadmap: designing a two-tier CA hierarchy with an offline Root CA and an online Intermediate CA, preparing the CA directory structure, writing the openssl.cnf configuration, signing CSRs, and applying best practices such as key escrow and validity period management. By the end of this episode you will have a CA ready to issue certificates.
The Root CA is the highest authority that signs itself. Because the entire chain of trust is rooted here, its private key must be guarded most tightly: offline and air-gapped, meaning it never touches the network. The root is used only when issuing an intermediate or signing a CRL.
A practical way to keep the root offline: store it on a computer that is not connected to the internet, keep encrypted backups in a safe place, and keep it away from day-to-day access. The less often the root key is switched on, the smaller its attack surface.
The Intermediate CA (Sub CA) is the authority that signs leaf certificates every day. Its private key may live on a network-connected server, but it must still be protected with strict permissions and limited access. With this separation, if the intermediate is compromised, the root remains safe and can revoke trust in the compromised intermediate.
Separating root and intermediate is an industry standard practice. Our entire lab follows this pattern: the root on a separate machine or isolated folder, the intermediate in a more active environment.
A traditional OpenSSL CA needs several marker files and folders. Prepare the structure for the intermediate:
mkdir -p intermediate-ca/{certs,crl,csr,newcerts,private}
touch intermediate-ca/index.txt
echo 1000 > intermediate-ca/serial
echo 1000 > intermediate-ca/crlnumber
chmod 700 intermediate-ca/privateThe function of each file: index.txt is the database of issued certificates, serial determines the next serial number, and crlnumber is for CRL numbering. All of these files will be managed automatically by openssl ca during signing.
The CA configuration is written in openssl.cnf. The following example is for the intermediate CA, complete with the CA_default section, policy, and certificate extensions:
[ ca ]
default_ca = CA_default
[ CA_default ]
dir = ./intermediate-ca
database = $dir/index.txt
new_certs_dir = $dir/newcerts
certificate = $dir/certs/intermediate.cert.pem
private_key = $dir/private/intermediate.key.pem
serial = $dir/serial
crlnumber = $dir/crlnumber
crl_dir = $dir/crl
default_md = sha256
policy = policy_loose
copy_extensions = copy
[ policy_loose ]
countryName = optional
stateOrProvinceName = optional
organizationName = optional
commonName = supplied
[ server_cert ]
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
[ client_cert ]
basicConstraints = CA:FALSE
keyUsage = digitalSignature
extendedKeyUsage = clientAuthThe [ CA_default ] section determines the location of all CA files and the policy used. The [ policy_loose ] section controls which CSR fields are required; in the example above only commonName is required. The [ server_cert ] and [ client_cert ] sections store extensions for server and client certificates, including serverAuth and clientAuth. The copy_extensions = copy line carries the SAN from the CSR into the certificate.
Once the CA is ready, we can sign CSRs. The core command:
openssl ca -config openssl.cnf -extensions server_cert \
-days 365 -notext -batch \
-in leaf/server.csr.pem \
-out leaf/server.cert.pemThe -extensions server_cert option uses the serverAuth extension from openssl.cnf, -days 365 sets the validity period, and -batch runs without interaction. Check the signing result:
openssl x509 -in leaf/server.cert.pem -noout -textNotice the Extended Key Usage section: it must contain serverAuth, and the Subject Alternative Name must contain the desired host name. For client identity, repeat with -extensions client_cert. The entire issuance history is recorded automatically in index.txt.
Key escrow is the storage of a copy of the private key in a trusted place for recovery purposes. For a private CA, store encrypted backups of the root and intermediate private keys on separate media, for example a USB locked in a safe or a secret manager. Without backups, losing a key means the CA must be rebuilt from scratch.
Make a habit of periodically testing your backups by trying to restore them, not just storing them. A backup that is never tested is only an illusion of security.
A CA's validity period should follow its role in the hierarchy. Common practice:
Short certificates limit the impact of a key leak and simplify service retirement. Get into the habit of recording the expiry date of every CA you issue, for example in an operational checklist.
In episode 4 you built a two-tier private CA: a tightly guarded offline Root CA, an online Intermediate CA for issuance, a directory structure with index and serial, openssl.cnf configuration, CSR signing with openssl ca, and key escrow and validity period management practices.
Key takeaways:
In episode 5, the final episode of this series, we will install the root certificate into the trust stores of systems, browsers, and applications, then distribute the certificate chain correctly. See you in the closing episode!