Skip to content

Obtaining and deploying CA-signed TLS certificates

Network automation talks to devices over secure channels — RESTCONF, gNMI, and HTTPS APIs all run over TLS. That security is only real if the certificate a device presents is trusted. This article covers how to earn that trust: the PKI pieces involved, how to generate a request with OpenSSL and enrol an IOS XE device, and how to keep certificates from silently expiring and taking your automation channel down with them.

Why self-signed is not enough

A self-signed certificate is cryptographically valid but trusted by nobody. To talk to an endpoint presenting one, a client has to disable verification — the exact condition behind the familiar certificate verify failed error. Turning verification off removes protection against man-in-the-middle attacks: anyone who can intercept the connection can present their own certificate and the client will accept it. That is tolerable in a throwaway lab and nowhere else.

The fix is a certificate signed by a Certificate Authority (CA) the client already trusts. Then verification stays on, and in a tool like Ansible you can safely keep validate_certs: true instead of papering over the problem with -k.

The PKI pieces

A handful of concepts carry the whole process:

  • Private key — generated on the endpoint and never leaves it. It proves ownership of the certificate.
  • CSR (Certificate Signing Request) — carries the public key plus identity information: the subject and, crucially, the Subject Alternative Name (SAN). This is what you send to the CA.
  • CA — the trusted authority that validates the request and signs it, returning the certificate.
  • Chain of trust — clients trust a root CA. The leaf certificate issued to your device is usually signed by an intermediate CA, so you deploy the leaf plus the intermediate chain.
  • SAN — modern clients validate the hostname against the SAN extension, not the legacy Common Name. A missing or wrong SAN is one of the most common real-world TLS failures.

The end-to-end process

The sequence is the same whether the endpoint is a Linux server or an IOS XE device:

  1. Generate a private key on the endpoint.
  2. Create a CSR from that key, including the correct subject and SAN.
  3. Submit the CSR to the CA for signing.
  4. The CA issues the signed leaf certificate plus its intermediate chain.
  5. Install the certificate and chain on the endpoint and bind it to the service.
  6. Ensure clients trust the CA root — then enable certificate validation.

Generating a key and CSR with OpenSSL

On a Linux host, two commands produce the key and the request. The -addext flag is the modern way to attach a SAN directly to the CSR:

# 1) generate a private key (stays on the host, mode 600)
openssl genrsa -out r1.key 2048

# 2) create a CSR with a subject and a SAN
openssl req -new -key r1.key -out r1.csr \
  -subj "/CN=r1.example.com" \
  -addext "subjectAltName=DNS:r1.example.com,IP:192.0.2.11"

# 3) send r1.csr to the CA; it returns r1.crt plus the chain

List every name and address the certificate must cover — DNS: entries for hostnames, IP: entries for literal addresses. For new deployments, a 2048-bit RSA key is the floor; 3072-bit RSA or an EC P-256 key (openssl ecparam -genkey -name prime256v1) is a better default.

Enrolling an IOS XE device

On IOS XE the same flow is expressed as a trustpoint: define the CA's enrollment URL, authenticate the CA (download and trust its certificate), then enrol (generate the CSR, submit it, install the signed certificate).

crypto key generate rsa modulus 2048
crypto pki trustpoint MY-CA
 enrollment url http://ca.example.com:80
 subject-name CN=r1.example.com
 rsakeypair MY-CA
!
crypto pki authenticate MY-CA     ! fetch + trust the CA certificate
crypto pki enroll MY-CA           ! generate CSR, submit, install signed cert

The order is fixed: authenticate before enroll. You must trust the CA before enrolling with it means anything.

Verifying what you deployed

Before and after deployment, confirm what the certificate actually contains and that it chains to a trusted root. Check the SAN and the expiry dates, then verify the chain:

# inspect the SAN and validity window
openssl x509 -in r1.crt -noout -ext subjectAltName
openssl x509 -in r1.crt -noout -dates

# verify the leaf chains to a trusted root via the intermediate
openssl verify -CAfile root-ca.pem -untrusted intermediate.pem r1.crt

A subtle trap when running your own CA: openssl ca/x509 will not copy the SAN from the CSR into the signed certificate unless you ask it to (-copy_extensions copyall, or the matching copy_extensions setting in the CA config). A certificate with the right Common Name but no SAN is rejected with a hostname-mismatch error — if validation fails despite a correct CN, the SAN is almost always what went missing.

Renewal: the silent-outage problem

Manual CSR handling does not scale, and the far more common operational failure is not a compromised key but a certificate that simply expires. An expired certificate gives no warning — one day RESTCONF or gNMI just starts failing with certificate verify failed, usually at an inconvenient hour.

Enrollment protocols automate both issuance and renewal. SCEP (Simple Certificate Enrollment Protocol) is widely supported on IOS XE trustpoints; EST (Enrollment over Secure Transport) is its modern, TLS-based successor. On IOS XE, auto-enroll regenerates the certificate before it lapses:

crypto pki trustpoint MY-CA
 enrollment url http://ca.example.com:80
 auto-enroll 75 regenerate   ! renew at 75% of lifetime, new key pair

Revocation handles the other case — a key compromised before expiry. A CRL (Certificate Revocation List) is a periodically published list the client downloads; OCSP (Online Certificate Status Protocol) lets the client ask the CA about a single certificate in real time. OCSP is timelier; CRLs are simpler and work offline.

Even with auto-renewal configured, monitor not-after dates and alert a week ahead. The cure for the 2 a.m. outage is process, not protocol.

Key takeaways

  • TLS is only meaningful if the certificate is CA-signed and trusted. A self-signed cert forces an unsafe verification bypass — fix the trust instead of disabling checks.
  • The private key never leaves the endpoint. The CSR carries the public key, subject, and SAN to the CA.
  • Modern clients validate the hostname against the SAN, not the Common Name — a missing SAN fails verification even when the CN is correct.
  • Deploy the leaf plus the intermediate chain so clients can build a path to a root they already trust.
  • On IOS XE, use a trustpoint: crypto pki authenticate then crypto pki enroll; automate renewal with SCEP/EST and auto-enroll.
  • Expiry, not revocation, is the common failure. Track not-after dates, alert early, and renew automatically.

Sources: RFC 6125 — service identity in TLS (SAN over CN), OpenSSL req manual, Cisco IOS PKI deployment and certificate rollover guide.