Certificate Lifecycle Management Guide
Certificates are the backbone of trust on the internet and within enterprise networks. They authenticate servers, encrypt communications, sign code, verify device identities, and enable mutual TLS between services. Yet certificate management remains one of the most operationally challenging aspects of identity and security.
The consequences of poor certificate management are severe and immediate. An expired certificate causes an outage, your website goes down, your API stops working, your VPN becomes inaccessible. A compromised certificate enables man-in-the-middle attacks. An over-issued certificate expands your attack surface. These are not theoretical risks: certificate-related outages make headlines regularly, affecting organizations from airlines to cloud providers.
This guide provides a complete approach to certificate lifecycle management, from PKI design through automated renewal and revocation.
What changed in 2024-2026
Three changes make automation mandatory rather than optional:
| Change | What it means | Source |
|---|---|---|
| Public TLS validity cuts (ballot SC-081v3, adopted 11 April 2025) | Maximum Subscriber Certificate validity is 200 days from 15 March 2026, 100 days from 15 March 2027, and 47 days from 15 March 2029. Domain validation reuse falls to 200, then 100, then 10 days on the same dates. | CA/Browser Forum ballot SC-081v3, Baseline Requirements 1.2.2 |
| Let's Encrypt ended OCSP | OCSP URLs were dropped from certificates on 7 May 2025 and the OCSP responders were turned off on 6 August 2025. Revocation checking for those certificates relies on CRLs. | Let's Encrypt, Ending OCSP Support |
| Post-quantum standards published | On 13 August 2024 NIST released FIPS 203 (ML-KEM, key encapsulation), FIPS 204 (ML-DSA, signatures), and FIPS 205 (SLH-DSA, backup signatures). | NIST announcement |
If any public certificate in your estate still renews through a ticket, the 2027 and 2029 steps will turn that into a quarterly or monthly outage risk. See also the certificate lifecycle and PKI glossary entries.
What You Will Learn
- PKI fundamentals and certificate hierarchy design
- Certificate issuance workflows for different use cases
- Automating certificate renewal with ACME and other protocols
- Revocation strategies: CRL, OCSP, and short-lived certificates
- Monitoring certificate health across your infrastructure
- Scaling certificate management for enterprise environments
Prerequisites
- PKI knowledge, Basic understanding of public key cryptography, X.509 certificates, and TLS.
- Certificate Authority (CA), Either a public CA (Let's Encrypt, DigiCert, Sectigo) or a private CA (AWS Private CA, HashiCorp Vault PKI, Microsoft AD CS, step-ca from Smallstep).
- Infrastructure access, Ability to deploy certificates to web servers, load balancers, API gateways, and application servers.
- DNS control, Required for ACME DNS-01 challenges and certificate validation.
- Monitoring platform, Prometheus, Datadog, Nagios, or similar for certificate expiry monitoring.
Architecture Overview
A certificate lifecycle management system consists of:
- Certificate Authority (CA): Issues and signs certificates. Can be a public CA (for internet-facing services) or a private CA (for internal services).
- Registration Authority (RA): Validates certificate requests before passing them to the CA. In many implementations, this is integrated into the CA.
- Certificate Inventory/Discovery: Scans the environment to find all deployed certificates and tracks their metadata (subject, issuer, expiry, location).
- Renewal Engine: Automates certificate renewal before expiry. Typically uses the ACME protocol for public certificates and custom automation for private certificates.
- Revocation Infrastructure: CRL distribution points and/or OCSP responders that communicate certificate revocation status.
- Monitoring and Alerting: Tracks certificate expiry dates and alerts operators before certificates expire.
Certificate hierarchy (for private PKI):
Root CA (offline, in HSM)
├── Intermediate CA - TLS (online, issues server certificates)
├── Intermediate CA - Client Auth (online, issues client certificates)
└── Intermediate CA - Code Signing (online, issues signing certificates)
The root CA is kept offline (not connected to any network) and is only used to sign intermediate CA certificates. The intermediate CAs are online and handle day-to-day issuance. If an intermediate CA is compromised, it can be revoked without replacing the root.
Step-by-Step Implementation
Step 1: Design Your PKI Hierarchy
For a private PKI, design the hierarchy before issuing any certificates:
pki_design:
root_ca:
common_name: "Contoso Root CA"
key_algorithm: "EC P-384"
validity: "20 years"
storage: "HSM (offline)"
usage: "Only signs intermediate CA certificates"
intermediate_cas:
- name: "Contoso TLS Issuing CA"
common_name: "Contoso TLS CA G1"
key_algorithm: "EC P-256"
validity: "5 years"
storage: "HSM (online)"
usage: "Issues TLS server and client certificates"
max_cert_validity: "90 days"
- name: "Contoso Service Mesh CA"
common_name: "Contoso Service Mesh CA G1"
key_algorithm: "EC P-256"
validity: "3 years"
storage: "HSM (online)"
usage: "Issues short-lived mTLS certificates for service mesh"
max_cert_validity: "24 hours"
Setting up a private CA with step-ca (open source):
# Initialize the CA
step ca init --name="Contoso Root CA" \
--dns="ca.contoso.internal" \
--address=":443" \
--provisioner="admin@contoso.com" \
--deployment-type="standalone"
# Configure certificate defaults
cat > ca.json << 'EOF'
{
"authority": {
"provisioners": [
{
"type": "ACME",
"name": "acme",
"forceCN": true
},
{
"type": "JWK",
"name": "admin@contoso.com",
"encryptedKey": "..."
}
],
"claims": {
"minTLSCertDuration": "1h",
"maxTLSCertDuration": "2160h",
"defaultTLSCertDuration": "720h"
}
}
}
EOF
Step 2: Implement Certificate Issuance
Different use cases require different issuance workflows:
Public-facing web servers (ACME with Let's Encrypt):
# Using certbot for ACME certificate issuance
certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials ~/.secrets/cloudflare.ini \
-d "*.example.com" \
-d "example.com" \
--preferred-challenges dns-01 \
--key-type ecdsa \
--elliptic-curve secp256r1
Internal services (Private CA with Vault PKI):
# Enable Vault PKI secrets engine
vault secrets enable -path=pki_int pki
vault secrets tune -max-lease-ttl=8760h pki_int
# Generate intermediate CA (signed by root)
vault write pki_int/intermediate/generate/internal \
common_name="Contoso TLS Issuing CA" \
key_type="ec" \
key_bits=256 \
ttl=43800h
# Configure a role for issuing TLS certificates
vault write pki_int/roles/internal-tls \
allowed_domains="contoso.internal" \
allow_subdomains=true \
max_ttl=2160h \
key_type="ec" \
key_bits=256 \
require_cn=false \
allowed_uri_sans="spiffe://contoso.internal/*"
# Issue a certificate
vault write pki_int/issue/internal-tls \
common_name="api.contoso.internal" \
alt_names="api.contoso.internal,api-v2.contoso.internal" \
ttl=720h
Kubernetes workloads (cert-manager):
# cert-manager Certificate resource
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: api-server-cert
namespace: production
spec:
secretName: api-server-tls
duration: 720h # 30 days
renewBefore: 168h # Renew 7 days before expiry
isCA: false
privateKey:
algorithm: ECDSA
size: 256
usages:
- server auth
- client auth
dnsNames:
- api.contoso.internal
- api.production.svc.cluster.local
issuerRef:
name: vault-issuer
kind: ClusterIssuer
group: cert-manager.io
Step 3: Automate Certificate Renewal
Manual certificate renewal does not scale and is the primary cause of certificate-related outages. Automate everything.
ACME-based renewal (for public certificates):
# Certbot automatic renewal (runs twice daily via systemd timer)
# /etc/systemd/system/certbot-renewal.timer
[Unit]
Description=Certbot renewal timer
[Timer]
OnCalendar=*-*-* 00,12:00:00
RandomizedDelaySec=3600
Persistent=true
[Install]
WantedBy=timers.target
# Certbot renewal with post-hook to reload services
certbot renew --deploy-hook "systemctl reload nginx"
Vault PKI automatic renewal:
import hvac
import time
from datetime import datetime, timedelta
class CertificateManager:
def __init__(self, vault_client, pki_mount, role):
self.vault = vault_client
self.pki_mount = pki_mount
self.role = role
self.current_cert = None
self.cert_expiry = None
def get_certificate(self, common_name, sans=None):
"""Get current certificate or issue a new one if expiring soon."""
if self.current_cert and self.cert_expiry > datetime.now() + timedelta(days=7):
return self.current_cert
# Issue new certificate
params = {
"common_name": common_name,
"ttl": "720h"
}
if sans:
params["alt_names"] = ",".join(sans)
response = self.vault.secrets.pki.generate_certificate(
name=self.role,
mount_point=self.pki_mount,
**params
)
self.current_cert = {
"certificate": response["data"]["certificate"],
"private_key": response["data"]["private_key"],
"ca_chain": response["data"]["ca_chain"],
"serial_number": response["data"]["serial_number"]
}
self.cert_expiry = datetime.fromtimestamp(response["data"]["expiration"])
return self.current_cert
def start_renewal_loop(self, common_name, sans=None, check_interval=3600):
"""Background loop that renews certificates before expiry."""
while True:
cert = self.get_certificate(common_name, sans)
days_until_expiry = (self.cert_expiry - datetime.now()).days
if days_until_expiry <= 7:
self.current_cert = None # Force renewal on next call
cert = self.get_certificate(common_name, sans)
deploy_certificate(cert) # Apply to web server, load balancer, etc.
time.sleep(check_interval)
Step 4: Implement Certificate Revocation
When a private key is compromised or a certificate is no longer needed, revocation must happen immediately.
Certificate Revocation List (CRL):
# Vault: Configure CRL
vault write pki_int/config/crl \
expiry=72h \
auto_rebuild=true \
auto_rebuild_grace_period=12h \
delta_rebuild_interval=15m
# Revoke a certificate
vault write pki_int/revoke serial_number="3a:cb:..."
CRLs are lists of revoked serial numbers that clients download periodically. They are simple but have drawbacks: the CRL can grow large, and there is a delay between revocation and the next CRL publish. For public certificates, CRLs are again the main mechanism: Let's Encrypt shut down its OCSP responders on 6 August 2025.
Online Certificate Status Protocol (OCSP):
OCSP provides real-time revocation checking and remains useful for private PKI where you control the responders. The client sends the certificate's serial number to the OCSP responder and gets back a signed "good," "revoked," or "unknown" response.
# Check OCSP status
openssl ocsp \
-issuer intermediate-ca.pem \
-cert server.pem \
-url http://ocsp.contoso.internal \
-resp_text
Short-lived certificates (the best approach):
The most elegant revocation strategy is to not need revocation at all. If certificates are valid for only 24 hours (or less), a compromised certificate expires before an attacker can make meaningful use of it. This approach requires strong renewal automation but eliminates the complexity of CRL/OCSP infrastructure.
# Short-lived certificate policy
policy:
service_mesh_certificates:
max_validity: "24h"
renewal_interval: "12h"
revocation_mechanism: "none" # Expiry handles it
server_certificates:
max_validity: "90d"
renewal_interval: "60d"
revocation_mechanism: "OCSP + CRL"
Step 5: Deploy Certificate Monitoring
# Prometheus certificate monitoring with blackbox exporter
# prometheus.yml
scrape_configs:
- job_name: 'tls-certificates'
metrics_path: /probe
params:
module: [tls_connect]
static_configs:
- targets:
- api.example.com:443
- app.example.com:443
- mail.example.com:465
- vpn.example.com:443
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- target_label: __address__
replacement: blackbox-exporter:9115
# Alert rules
groups:
- name: certificate-alerts
rules:
- alert: CertificateExpiringSoon
expr: probe_ssl_earliest_cert_expiry - time() < 30 * 24 * 3600
for: 1h
labels:
severity: warning
annotations:
summary: "Certificate for {{ $labels.instance }} expires in less than 30 days"
- alert: CertificateExpiringCritical
expr: probe_ssl_earliest_cert_expiry - time() < 7 * 24 * 3600
for: 1h
labels:
severity: critical
annotations:
summary: "Certificate for {{ $labels.instance }} expires in less than 7 days"
- alert: CertificateExpired
expr: probe_ssl_earliest_cert_expiry - time() < 0
for: 5m
labels:
severity: critical
annotations:
summary: "Certificate for {{ $labels.instance }} has EXPIRED"
Certificate inventory scanning:
#!/bin/bash
# Scan network for TLS certificates and record metadata
TARGETS_FILE="targets.txt"
OUTPUT_FILE="cert_inventory.csv"
echo "host,port,subject,issuer,not_before,not_after,serial,days_remaining" > "$OUTPUT_FILE"
while IFS=: read -r host port; do
cert_info=$(echo | openssl s_client -connect "$host:$port" -servername "$host" 2>/dev/null | \
openssl x509 -noout -subject -issuer -startdate -enddate -serial 2>/dev/null)
if [ -n "$cert_info" ]; then
subject=$(echo "$cert_info" | grep "subject=" | sed 's/subject=//')
issuer=$(echo "$cert_info" | grep "issuer=" | sed 's/issuer=//')
not_before=$(echo "$cert_info" | grep "notBefore=" | sed 's/notBefore=//')
not_after=$(echo "$cert_info" | grep "notAfter=" | sed 's/notAfter=//')
serial=$(echo "$cert_info" | grep "serial=" | sed 's/serial=//')
expiry_epoch=$(date -d "$not_after" +%s 2>/dev/null || date -j -f "%b %d %T %Y %Z" "$not_after" +%s 2>/dev/null)
now_epoch=$(date +%s)
days_remaining=$(( (expiry_epoch - now_epoch) / 86400 ))
echo "$host,$port,$subject,$issuer,$not_before,$not_after,$serial,$days_remaining" >> "$OUTPUT_FILE"
fi
done < "$TARGETS_FILE"
Step 6: Implement Certificate Pinning (Where Appropriate)
Certificate pinning adds a layer of defense by ensuring your application only trusts specific certificates or CAs, rather than any CA in the system trust store.
// Node.js: Certificate pinning for API calls
const https = require('https');
const crypto = require('crypto');
const PINNED_FINGERPRINTS = [
'sha256/YLh1dUR9y6Kja30RrAn7JKnbQG/uEtLMkBgFF2Fuihg=', // Current
'sha256/sRHdihwgkaib1P1gN7akqEC2K0VQ3oL+ship1pOv28I=', // Backup
];
const agent = new https.Agent({
checkServerIdentity: (hostname, cert) => {
const fingerprint = crypto
.createHash('sha256')
.update(cert.raw)
.digest('base64');
const pinned = `sha256/${fingerprint}`;
if (!PINNED_FINGERPRINTS.includes(pinned)) {
throw new Error(`Certificate pin mismatch for ${hostname}`);
}
}
});
Use pinning sparingly and always include a backup pin (for the next certificate you will rotate to). Pinning the wrong thing or failing to update pins before certificate rotation causes outages.
Configuration Best Practices
- Use EC keys over RSA. ECDSA P-256 provides equivalent security to RSA-2048 with smaller keys and faster operations. Use P-384 for root and intermediate CAs.
- Keep certificate validity short. 90 days or less for public-facing TLS (the public maximum is 200 days now and 47 days from March 2029), 30 days for internal services, 24 hours or less for service mesh. Shorter validity reduces the window of exposure from a compromised key.
- Automate renewal at 2/3 of the certificate lifetime. For a 90-day certificate, renew at day 60. This provides a 30-day buffer for troubleshooting if renewal fails.
- Always include SAN entries. Modern browsers require Subject Alternative Names (SANs). The Common Name (CN) is deprecated for hostname validation.
- Separate CAs for different purposes. Use separate intermediate CAs for TLS, client authentication, and code signing. This limits the blast radius of a CA compromise.
- Store CA keys in HSMs. Hardware Security Modules prevent key extraction and provide audit logging. At minimum, use an HSM for the root CA.
Testing and Validation
- Issuance testing: Issue a certificate and verify all fields (subject, SANs, key usage, extended key usage, validity, chain).
- Renewal testing: Set a certificate's validity to 2 hours and verify that automated renewal kicks in after 1 hour.
- Revocation testing: Revoke a certificate and verify that clients reject it (check CRL download or OCSP response).
- Chain validation testing: Present the full certificate chain to a client and verify trust. Then remove the intermediate CA and verify the client rejects the connection.
- Expiry alerting testing: Set a certificate to expire in 6 days and verify the critical alert fires.
- CA failover testing: Simulate the primary issuing CA being unavailable. Verify that a standby CA can take over issuance.
Common Pitfalls and Troubleshooting
| Problem | Cause | Solution |
|---|---|---|
| "Certificate not trusted" | Incomplete chain; intermediate CA not sent | Configure the server to send the full chain (server cert + intermediate) |
| Certificate expires unexpectedly | Renewal automation failed silently | Monitor renewal job success/failure, not just certificate expiry |
| ACME challenge fails | DNS propagation delay or firewall blocking | Use DNS-01 challenges with low TTL; verify firewall allows CA to reach your server |
| Wildcard cert used everywhere | Single compromised key exposes all subdomains | Use specific certificates per service; limit wildcard use to CDN/load balancer |
| "Certificate key too weak" | RSA-1024 or similar deprecated key | Use EC P-256 or RSA-2048 minimum; audit all certificates for weak keys |
| mTLS handshake fails | Client certificate not signed by trusted CA | Verify the server's trust store includes the client CA |
Security Considerations
- Protect private keys. The private key is the most sensitive artifact. Store it in a file with restricted permissions (chmod 600), in a secrets vault, or in an HSM. Never transmit private keys over unencrypted channels.
- Root CA must be offline. The root CA private key should never be on a network-connected machine. Keep it in an HSM in a physical safe. Only bring it online to sign new intermediate CA certificates (as a rough planning estimate, once every 3-5 years).
- Certificate Transparency (CT) logs. For public certificates, submission to CT logs is mandatory. Monitor CT logs for unauthorized certificates issued for your domains, this can detect a compromised CA or a rogue certificate issuance.
- CAA DNS records. Publish Certificate Authority Authorization (CAA) DNS records to restrict which CAs can issue certificates for your domain.
- Quantum readiness. Current certificate algorithms (RSA, ECDSA) will be vulnerable to quantum computers. Begin planning for post-quantum cryptography (PQC) migration against the standards NIST published in August 2024: FIPS 203 (ML-KEM), FIPS 204 (ML-DSA), and FIPS 205 (SLH-DSA). Track your CA, HSM, and TLS library PQC roadmaps.
Conclusion
Certificate lifecycle management is an operational discipline, not a one-time project. Certificates are constantly being issued, renewed, and revoked. The organizations that avoid certificate-related outages are those that invest in automation, monitoring, and short certificate lifetimes.
Start by gaining visibility: discover every certificate in your environment and monitor their expiry dates. Then automate renewal: use ACME for public certificates and Vault PKI or cert-manager for internal certificates. Finally, shorten lifetimes: move toward 90-day public certificates and 24-hour internal certificates. Each step reduces risk and operational burden.
Frequently asked questions
- What is certificate lifecycle management?
- Certificate lifecycle management is the ongoing process of discovering, issuing, renewing, revoking, and monitoring every X.509 certificate in your environment. It covers public certificates for internet-facing services and private certificates for internal services, mTLS, devices, and code signing. The goal is that no certificate expires unnoticed, no compromised certificate stays trusted, and renewal runs through automation rather than tickets.
- How short should certificate lifetimes be?
- As short as your automation supports, and public TLS is being forced shorter anyway. Under CA/Browser Forum ballot SC-081 the maximum public TLS validity fell to 200 days on 15 March 2026, drops to 100 days on 15 March 2027, and reaches 47 days on 15 March 2029. Internal services with strong automation can run 30 days or less, and service mesh SVIDs hours.
- When should a certificate be renewed?
- Automate renewal at two thirds of the certificate lifetime. For a 90-day certificate, renew at day 60, which leaves a 30-day buffer to troubleshoot if renewal fails. Monitor the renewal job's success or failure, not just the expiry date, because silent renewal failures are a common cause of certificates expiring unexpectedly.
- What is the difference between CRL and OCSP?
- A Certificate Revocation List is a list of revoked serial numbers that clients download periodically, so it can grow large and lags behind each revocation until the next publish. OCSP is a real-time query that returns a signed good, revoked, or unknown answer. Public CAs are moving away from OCSP: Let's Encrypt removed OCSP URLs from its certificates in May 2025 and turned its responders off in August 2025, relying on CRLs. Short-lived certificates reduce the need for either.
- Why should the root CA be kept offline?
- Because a compromised root means replacing trust everywhere. Keep the root CA private key in an HSM on a machine that is never network connected, and bring it online only to sign intermediate CA certificates. Intermediates handle day-to-day issuance, so if one is compromised you revoke it without replacing the root. Use separate intermediates for TLS, client authentication, and code signing.
- Do I need a private CA?
- Yes, if internal services use mTLS, client certificate authentication, device certificates, or internal code signing. Public CAs issue certificates only for publicly resolvable names and under CA/Browser Forum rules, including the shrinking validity limits, so they do not fit internal naming or custom profiles. Run a private CA such as AWS Private CA, Vault PKI, Microsoft AD CS, or step-ca for internal trust.
- How do I prepare for post-quantum cryptography?
- Start by inventorying every certificate and key with its algorithm, key size, lifetime, and owner, because you cannot migrate what you cannot find. NIST published the first post-quantum standards in August 2024: FIPS 203 (ML-KEM), FIPS 204 (ML-DSA), and FIPS 205 (SLH-DSA). Track your CA, HSM, and TLS library roadmaps, and test hybrid key exchange where your stack supports it.
- What is ACME and should I use it?
- ACME (Automated Certificate Management Environment, RFC 8555) is the protocol Let's Encrypt and many other CAs use for automated issuance and renewal. Use it for all public certificates, since 100-day and later 47-day maximum lifetimes make manual renewal impractical. Consider it for private certificates too: step-ca and several enterprise CAs support ACME, so one renewal client covers both.
Related on Start with Identity
- ArticleCertificate Lifecycle Management: What Breaks and How to Automate It
Certificate management explained: discovery, issuance, renewal, and revocation across public and private PKI, why the CA/Browser Forum schedule to 47-day certif
- GuideMachine Identity Management Guide
A complete guide to managing machine identities including certificates, service accounts, API keys, secrets rotation, PKI setup, and machine-to-machine authenti
- GlossaryACME (Automated Certificate Management Environment)
ACME (Automated Certificate Management Environment) is the IETF protocol, [RFC 8555](https://www.rfc-editor.org/rfc/rfc8555) (March 2019, Proposed Standard), th
- ArticleTop 6 Open-Source PKI and Certificate Management Tools
The best open-source PKI tools in 2026, from EJBCA and step-ca to Dogtag, cert-manager, OpenXPKI, and Boulder, compared on protocol support, automation, and who
- GlossaryUser Lifecycle Management
User lifecycle management is the automated creation, change and removal of a person's accounts and access as their relationship with an organization changes, dr
- GuideUser Lifecycle Management: Automating Joiner-Mover-Leaver Processes
Complete guide to automating the user lifecycle from onboarding through role changes to offboarding, including orphan account detection and provisioning workflo