How do I design a two-tier PKI with an offline root CA?
By Vitalii Shumylo · 5 October 2026 · 8 min read
Build a standalone root CA that never joins the domain and stays switched off. It signs one certificate, for an enterprise subordinate CA that's domain-joined and does all the everyday issuing. Publish the root's CRL and certificate over HTTP, give the root a long CRL interval, and check the whole chain in PKIView.
We'll go through the design decisions, then install the root, set its CRL and validity, build the issuing CA, and finish on a green PKIView.
Why two tiers, and why the root stays offline
The root CA's private key is the one thing that can't be replaced without re-trusting every certificate in the company. So we keep it on a machine that's off, not domain-joined, and ideally a VM whose disk sits in a safe or on an encrypted share.
That's also why the root has to be a standalone CA. An enterprise CA needs Active Directory and has to stay online to talk to it, which defeats the point. The issuing CA is the opposite: an enterprise subordinate that reads certificate templates from AD and handles autoenrolment for users and computers.
I'd stop at two tiers for most organisations. A three-tier design (root, policy CA, issuing CAs) adds a machine to patch and another CRL to keep alive, and it only pays off when you need separate policies for separate business units.
The root signs the issuing CA and the root CRL - nothing else, ever.
In our lab that's ROOTCA (workgroup, no network once it's built) and CA1 (192.168.10.20, a member of corp.learnitlessons.com), with IIS on CA1 answering as pki.corp.learnitlessons.com (a CNAME in DNS).
Validity periods: recommendations, not rules
Before installing anything, decide the lifetimes, because the root's lifetime is baked in at install time. A CA can't issue a certificate that outlives its own, so each tier needs headroom over the one below it.
These are common starting points, not Microsoft rules - adjust them to your own policy:
| item | a typical choice | why |
|---|---|---|
| root CA certificate | 20 years | it's re-trusted everywhere when it changes |
| issuing CA certificate | 10 years | about half the root's, so renewal happens well inside the root's life |
| root CRL | 52 weeks | the root comes online once a year, at least |
| issuing CA CRL | 1 week, delta 1 day | it's online, so short intervals cost nothing |
The decision I make here is the key length: 4096-bit RSA with SHA256 for the root and issuing CA. Some older devices struggle with 4096-bit chains, so if you've got legacy kit, test before you commit.
Install the offline root
With the lifetimes agreed, ROOTCA gets the role. This installs AD CS and creates a standalone root with a 20-year certificate.
Install-WindowsFeature -Name ADCS-Cert-Authority -IncludeManagementTools
Install-AdcsCertificationAuthority -CAType StandaloneRootCA -CACommonName 'Corp-Root-CA' `
-CryptoProviderName 'RSA#Microsoft Software Key Storage Provider' -KeyLength 4096 `
-HashAlgorithmName SHA256 -ValidityPeriod Years -ValidityPeriodUnits 20
Check it worked by asking the CA to describe itself:
certutil -cainfo name
Expected output: CA name: Corp-Root-CA, then CertUtil: -CAInfo command completed successfully.
Many admins also drop a CAPolicy.inf into C:\Windows before this step to set the renewal key length and validity. It's a good habit, and the course covers it, but the cmdlet parameters above are enough for a first build.
Set the root's CRL interval and the CDP/AIA URLs
Now that the root exists, we tell it how long its CRLs last and where clients will find them. Every certificate the root signs carries those URLs, so this must happen before it signs the issuing CA.
This block sets a 52-week CRL, turns delta CRLs off (an offline CA can't publish them), and gives signed certificates a 10-year life:
certutil -setreg CA\CRLPeriodUnits 52
certutil -setreg CA\CRLPeriod "Weeks"
certutil -setreg CA\CRLDeltaPeriodUnits 0
certutil -setreg CA\ValidityPeriodUnits 10
certutil -setreg CA\ValidityPeriod "Years"
Next, the locations. I use HTTP only. LDAP paths work only for domain members, and a non-domain device or a partner can't read them, while HTTP works for everyone. Flag 1 means "publish here", flag 2 means "write this URL into issued certificates".
certutil -setreg CA\CRLPublicationURLs "1:C:\Windows\System32\CertSrv\CertEnroll\%3%8%9.crl\n2:http://pki.corp.learnitlessons.com/CertEnroll/%3%8%9.crl"
certutil -setreg CA\CACertPublicationURLs "1:C:\Windows\System32\CertSrv\CertEnroll\%1_%3%4.crt\n2:http://pki.corp.learnitlessons.com/CertEnroll/%1_%3%4.crt"
Restart-Service -Name certsvc
certutil -crl
certutil -crl publishes a fresh CRL with the new settings. Check it in C:\Windows\System32\CertSrv\CertEnroll: you should see Corp-Root-CA.crl and ROOTCA_Corp-Root-CA.crt. Open the CRL and the Next update date should be about a year away.
Pause and think
The root CRL lasts 52 weeks. What happens if nobody switches ROOTCA on for 13 months?
Answer: the root CRL expires, revocation checks on the issuing CA's certificate fail, and clients start rejecting every certificate below it. Put a calendar reminder a few weeks before Next update, start ROOTCA, run certutil -crl, and copy the new file to the web server.
Build the enterprise subordinate issuing CA
So the root is ready to sign. Before CA1 can install, the domain must trust the root, and the web server must hold its files. Copy the .crt and .crl from ROOTCA (by removable media, never a network share) to CA1's C:\inetpub\wwwroot\CertEnroll folder, then publish the root certificate to AD from CA1:
certutil -dspublish -f C:\inetpub\wwwroot\CertEnroll\ROOTCA_Corp-Root-CA.crt RootCA
Then install the issuing CA. It can't finish on its own: it writes a request file for the root to sign.
Install-WindowsFeature -Name ADCS-Cert-Authority -IncludeManagementTools
Install-AdcsCertificationAuthority -CAType EnterpriseSubordinateCA -CACommonName 'Corp-Issuing-CA' `
-CryptoProviderName 'RSA#Microsoft Software Key Storage Provider' -KeyLength 4096 `
-HashAlgorithmName SHA256 -OutputCertRequestFile C:\CA1-request.req
Carry the request to ROOTCA. A standalone CA holds requests as pending, so we submit, approve and retrieve it. The request ID comes back from the first command; here it's 2.
certreq -submit -config 'ROOTCA\Corp-Root-CA' C:\CA1-request.req
certutil -resubmit 2
certreq -retrieve -config 'ROOTCA\Corp-Root-CA' 2 C:\CA1-cert.crt
Back on CA1, install the signed certificate and start the service:
certutil -installcert C:\CA1-cert.crt
Start-Service -Name certsvc
Give CA1 its own HTTP CDP and AIA the same way, with a 1-week CRL and a 1-day delta, and two changes: point the local publish paths at C:\inetpub\wwwroot\CertEnroll so IIS serves what the CA writes, and, because CA1 has delta CRLs, use flag 65 (publish base and delta CRLs here) on the local CRL path and 6 (write the URL into certificates and into CRLs, so clients find the delta) on the HTTP one. Then shut ROOTCA down.
Check the chain in PKIView
With both tiers built, the proof is the Enterprise PKI console. On CA1, run pkiview.msc. Under Corp-Root-CA and Corp-Issuing-CA, every row - CA Certificate, AIA Location #1, CDP Location #1 - should read OK.
A red "Unable to download" means a URL in a certificate doesn't match a real file on the web server. That's the one to fix before you issue a single user certificate, because the URL is already baked into the CA certificate.
Common mistake: the CRL that won't download over IIS
What it looks like: PKIView shows OK for the base CRL but Unable to download for the delta CRL on the issuing CA, and some clients fail revocation checks.
Why it happens: delta CRL file names end in +, and IIS request filtering blocks double escaping by default, so it refuses the file with a 404.
The fix: allow double escaping on the CertEnroll folder only, not the whole site, then refresh PKIView.
Import-Module -Name WebAdministration
Set-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' -Location 'Default Web Site/CertEnroll' -Filter /system.webServer/security/requestFiltering -Name allowDoubleEscaping -Value $true
The delta row turns to OK.
FAQ
Can the offline root CA be a domain member?
It can, but I wouldn't. Joining ties the root to AD, Group Policy and domain admins, which is exactly the exposure we switched it off to avoid. Standalone in a workgroup is the clean choice.
Do I need OCSP as well as CRLs?
Not for a first build. CRLs work everywhere. Add an Online Responder on the issuing tier later if your CRLs grow large or clients need fresher answers; the root rarely needs one.
What happens when the issuing CA certificate is close to expiry?
You renew it, ideally at about half its life, by bringing ROOTCA online to sign the renewal request. With a 10-year issuing CA under a 20-year root, there's plenty of room.
Is a hardware security module required?
No, a software key storage provider works. An HSM protects the root key better, and many regulated organisations require one, but it's a cost and policy decision, not a technical requirement.
Go deeper
The Public Key Infrastructure (PKI) Complete Course builds this two-tier design step by step in a Hyper-V lab: CAPolicy.inf files, the offline root's CDP and AIA, air-gapped file transfer, the enterprise subordinate install, and IIS with delta CRL configuration. It also covers certificate templates, autoenrolment, key archival and troubleshooting CAs, and it repeats the build on Server Core.
Public Key Infrastructure (PKI) Complete Course
Coupon SEP30SALE: $9.99 until 10/05/2026
Get the course for $9.99