PKI is one of those topics that everyone nods along to and almost nobody has actually built. You read about certificate authorities, trustpoints, enrollment, and revocation, and it all stays abstract because the tooling feels heavy: a Windows domain, AD CS, a public CA that wants money and a DNS record. So the chapter gets skimmed, and then one day a certificate-authenticated IPsec tunnel refuses to come up and you are debugging something you never actually saw work.
Here is the shortcut. You do not need any of that. A Cisco IOS XE router will happily act as a full certificate authority, issue real X.509 certificates, and hand them to other routers over HTTP. It takes about six lines of config. In our CCIE Security lab we built exactly that on a cat8000v called CA1, issued real certificates from it, and then used those certificates to authenticate an IKEv2 tunnel with no pre-shared key anywhere in the configuration. If you are working through the IPsec VPN pillar, this is the missing piece that makes certificate authentication stop being theory.
What a Certificate Authority Actually Does
Strip away the ceremony and a CA does two things.
First, it issues itself a certificate. This is the root, and it is self-signed: the CA vouches for itself, because there is nobody above it to do the vouching. In our lab this was serial number 01. That self-signed CA certificate is what every client will eventually install and trust. Everything downstream hangs off it.
Second, it signs certificate signing requests (CSRs) from clients. A router generates an RSA keypair, keeps the private key, wraps the public key plus a subject name into a CSR, and sends it to the CA. The CA checks it (or, in a lab, does not check it at all), signs it with the CA private key, and hands back an identity certificate. In our lab GM1 got serial 02 and GM2 got serial 03.
The Config: Six Lines and a Reload of Your Assumptions
This is the CA server we built on CA1 (a cat8000v at 10.100.0.31 on the lab WAN core):
CA1(config)#crypto pki server PLZ-CA
database level complete
issuer-name CN=PLZ-CA,O=PingLabz,C=US
grant auto
lifetime certificate 730
lifetime ca-certificate 1825
no shutdownLine by line:
show command.<serial>.cer. The alternatives (minimal, names) store less. You want complete if you ever intend to revoke anything, because you need the certificate to revoke it.About grant auto, honestly
grant auto means the CA signs anything that asks. Any device that can reach TCP/80 on the CA and speak SCEP gets a valid certificate with whatever subject name it claimed. In a closed lab that is exactly what you want, because the alternative is manually approving every enrollment while you are trying to learn something else.
In production it is the opposite of what you want. The correct setting is grant none, which parks every request in a queue. You then inspect the request, confirm out of band that the device asking is the device you think it is, and approve it explicitly with crypto pki server PLZ-CA grant <req-id>. That manual step is not bureaucracy, it is the entire point: a CA that signs anything is a CA that will happily issue a certificate to an attacker who plugged a laptop into your network and claimed to be a router. The certificate would be cryptographically perfect and completely worthless.
Before: Configured but Disabled
Type the config but do not enable the server, and this is what you get. This is real output from CA1:
CA1#show crypto pki server
Certificate Server PLZ-CA:
Status: disabled
State: initial
Server's configuration is unlocked (enter "no shut" to lock it)
Issuer name: CN=PLZ-CA,O=PingLabz,C=US
CA cert fingerprint: -Not found-
Granting mode is: autoFour things are being told to you here.
Status: disabled / State: initial. The CA exists as configuration but has done nothing. It has no keypair and no certificate.
Server's configuration is unlocked (enter "no shut" to lock it). This is the interesting one. While the server is shut down, you can freely change the issuer name, the lifetimes, the whole shape of the CA. The moment you enable it, the identity-defining parameters lock, because the CA is about to generate a self-signed certificate that bakes them in. You cannot rename an issuer after it has signed certificates without invalidating everything downstream. IOS enforces that for you.
CA cert fingerprint: -Not found-. There is no CA certificate yet, so there is nothing to fingerprint. This field is going to matter enormously in a minute.
Granting mode is: auto. Exactly what we asked for, and exactly what we would not ask for in production.
After: A Live CA With a Real Fingerprint
Now enable it with no shutdown, answer the prompts, and look again:
CA1#show crypto pki server
Certificate Server PLZ-CA:
Status: enabled
State: enabled
Server's configuration is locked (enter "shut" to unlock it)
Issuer name: CN=PLZ-CA,O=PingLabz,C=US
CA cert fingerprint: 50AE2189 0FC62684 1418DEF0 B0EB714A
Granting mode is: auto
Last certificate issued serial number (hex): 3
CA certificate expiration timer: 09:04:14 UTC Jul 12 2031
CRL NextUpdate timer: 15:04:24 UTC Jul 13 2026
Current primary storage dir: nvram:
Database Level: Complete - all issued certs written as <serialnum>.cerWalk the new fields:
Status: enabled / State: enabled. The CA has generated its RSA keypair, signed its own root certificate, and is now listening for enrollment requests over SCEP on HTTP.
Server's configuration is locked. As promised. The issuer name is now cast in the root certificate.
CA cert fingerprint: 50AE2189 0FC62684 1418DEF0 B0EB714A. Memorize this idea, not the value. This is the fingerprint of the CA's self-signed root certificate. When a client later runs crypto pki authenticate, IOS will display a fingerprint and ask whether you accept the certificate. That fingerprint must match this one. Comparing them, out of band, is the only thing standing between you and trusting an impostor CA. We go into this in depth in the walkthrough on certificate authentication for IPsec, but note that the value you compare against originates right here, on the CA itself.
Last certificate issued serial number (hex): 3. Three certificates exist in this CA's world. Serial 01 is the CA's own self-signed root. Serial 02 is GM1's identity certificate. Serial 03 is GM2's. Serials are sequential and never reused, because a serial number plus an issuer name is the unique key for a certificate, and that is precisely what a revocation list refers to.
CA certificate expiration timer: 09:04:14 UTC Jul 12 2031. Five years out, which is our lifetime ca-certificate 1825. When this expires, every certificate chaining to it dies with it. Put it in a calendar.
CRL NextUpdate timer. The CA is publishing a certificate revocation list and telling clients when to come back for a fresh copy. In our lab nothing checks it (more on that shortly), but the CA is dutifully maintaining it anyway.
Current primary storage dir: nvram:. The certificate database, and the CA's private key, live in the router's NVRAM. Sit with that for a second. We will come back to it.
Gotcha 1: no shutdown Is Interactive, and That Kills Automation
You cannot push a CA server config from a script. Not with a naive config push, anyway.
no shutdown under crypto pki server is an interactive command. IOS stops and prompts you for a passphrase, which is used to protect the CA's private key in NVRAM. It then asks you to confirm it. A configuration-automation tool that streams lines at a device and does not handle prompts will hang, time out, or silently leave the CA disabled while reporting success. We hit exactly this: the config went in fine, the server stayed down, and we ended up driving no shutdown from a real interactive SSH session to get past the passphrase prompt.
The lesson generalizes past PKI. Crypto commands in IOS have a habit of being interactive precisely because they involve secrets that should not sit in a config file, and secrets that should not sit in a config file are exactly the things your automation pipeline is worst at handling. If you are building CA bring-up into an automated workflow, you need something that speaks expect-style prompt handling, not a template renderer.
Gotcha 2: PKI Needs a Clock. Set It First.
This is the one that produces the most baffling failures, and here is the router telling you about it in plain English:
%PKI-2-NON_AUTHORITATIVE_CLOCK: PKI functions can not be initialized until an
authoritative time source, like NTP, can be obtained.Certificates are time-bound objects. Every certificate carries a start date and an end date, and every validation checks the current time against them. If a device's clock is wrong, one of two things happens: it decides a perfectly valid certificate is not yet valid, or it decides an expired certificate is fine. Both are wrong, and neither of them produces an error message that says "your clock is wrong". You get an authentication failure, or a tunnel that will not establish, and you go hunting through crypto debugs for an hour.
Do this before you touch any PKI command, on the CA and on every client:
clock set 09:00:00 Jul 13 2026
ntp server 10.100.0.11Set the clock manually to get past the bootstrap problem, then point at NTP so it stays right. In a lab, one device with a stable clock acting as the NTP master for everyone else is enough. In production, this is non-negotiable infrastructure: your PKI is only as trustworthy as your time.
What a Lab CA Is Not
Everything above is genuinely real PKI. The certificates are real X.509 certificates, the signatures are real RSA signatures, and the authentication that follows is real cryptographic authentication. But be honest with yourself about the gap between this and a CA you would put behind a bank.
revocation-check none). Revocation that nobody checks is revocation that does not exist.What To Do With It Next
A CA on its own is inert. It becomes interesting the moment a client enrolls with it and then uses the resulting certificate to prove its identity to a peer. That is the payoff, and it is the subject of the follow-up: certificate authentication for IPsec, where GM1 and GM2 enroll against this exact CA and then bring up an IKEv2 tunnel whose configuration contains no pre-shared key at all. The IKEv2 SA on that tunnel says Auth sign: RSA instead of Auth sign: PSK, and that single word is what all of this was for.
If IKEv2 itself is still fuzzy, start with how IKEv2 works and the wider IPsec VPN guide, which covers the full progression from pre-shared keys through certificates to GETVPN.
Key Takeaways
- An IOS XE router is a fully functional certificate authority. Six lines of config under
crypto pki serverand you have a working CA issuing real X.509 certificates. No AD CS, no public CA, no money. - The CA issues itself a self-signed root certificate (serial 01 in our lab), then signs client CSRs sequentially (02 for GM1, 03 for GM2). Serial number plus issuer name is what uniquely identifies a certificate, and it is what a CRL revokes.
Server's configuration is unlockedbecomeslockedwhen you enable the server, because the issuer name is now baked into the self-signed root. Get the issuer name right before you enable.- The
CA cert fingerprintfromshow crypto pki serveris the value clients must verify out of band when they authenticate the trustpoint. It is the anchor of the entire trust chain. no shutdownon a crypto PKI server is interactive: it prompts for a passphrase protecting the CA private key. A config-push tool that cannot handle prompts will not bring your CA up. Drive it from a real session.- PKI needs an authoritative clock.
%PKI-2-NON_AUTHORITATIVE_CLOCKmeans PKI will not even initialize. Set the clock or run NTP on the CA and every client before you touch a single PKI command. grant autois a lab convenience that signs anything that asks. Production wantsgrant noneand manual approval of every request.- A router CA has no HSM, no offline root, no meaningful revocation distribution, and its private key lives in NVRAM. It is excellent for learning and internal labs. It is not a production trust anchor.