Stage 3 · Build
TLS & Certificate Management
Certificate Management
Let's Encrypt, cert-manager, and certificate lifecycle automation.
Let's Encrypt and ACME
Let's Encrypt is a free, automated CA that uses the ACME protocol to issue certificates. It revolutionized TLS adoption by making certificates free and automatable. Most modern certificates on the web are from Let's Encrypt.
HTTP-01: Place a file at http://example.com/.well-known/acme-challenge/<token>
Server verifies you control the domain's web server
DNS-01: Create a TXT record _acme-challenge.example.com=<validation>
Server verifies you control DNS (supports wildcards)
TLS-ALPN-01: Present a self-signed cert during TLS handshake
Server verifies during TLS connectionDNS-01 is required for wildcard certificates. HTTP-01 is simplest for single domains. TLS-ALPN-01 works when you cannot serve HTTP on port 80. Choose based on your infrastructure constraints.
Certbot in Practice
# Get a certificate (interactive)
sudo certbot --nginx
# Get a certificate with DNS challenge
sudo certbot certonly --manual --preferred-challenges dns \
-d example.com -d *.example.com
# Renew all certificates
sudo certbot renew
# Check certificate status
sudo certbot certificates
# Dry-run renewal (test without actually renewing)
sudo certbot renew --dry-run
# View the cron job or systemd timer
systemctl list-timers | grep certbotCertbot automatically configures your web server (Nginx, Apache) and sets up a cron job or systemd timer for renewal. The renewal happens before expiry — typically 30 days before.
Run certbot renew --dry-run regularly to verify that renewal will succeed. If the ACME challenge fails (expired DNS record, firewall blocking port 80), the dry run will catch it before your certificate actually expires.
cert-manager for Kubernetes
cert-manager is the standard for certificate management in Kubernetes. It watches Certificate resources, communicates with ACME or other CAs, creates TLS Secrets, and handles renewal automatically.
# Install cert-manager
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.14.0/cert-manager.yaml
# Create a ClusterIssuer for Let's Encrypt
cat <<EOF | kubectl apply -f -
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: admin@example.com
privateKeySecretRef:
name: letsencrypt-prod
solvers:
- http01:
ingress:
class: nginx
EOF
# Request a certificate
cat <<EOF | kubectl apply -f -
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: example-com
namespace: default
spec:
secretName: example-com-tls
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
dnsNames:
- example.com
- www.example.com
EOFcert-manager creates a Certificate resource, performs the ACME challenge, and stores the resulting certificate in a Secret (example-com-tls in this case). Your Ingress references this Secret for TLS.
Running an Internal CA
# Initialize cfssl
cfssl gencert -initca ca-csr.json | cfssljson -bare ca
# Sign a certificate
cfssl sign -ca ca.pem -ca-key ca-key.pem -config ca-config.json \
-profile server example-csr.json | cfssljson -bare example
# Create self-signed with OpenSSL
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout ca-key.pem -out ca.pem \
-subj "/CN=My Internal CA"Internal CAs are useful for service-to-service mTLS, development environments, and IoT device identity. cfssl (from Cloudflare) simplifies CA management. For production, consider HashiCorp Vault as a CA.
Certificate Rotation Strategies
Zero-downtime rotation:
1. Generate new certificate
2. Deploy new cert alongside old cert
3. Server accepts both old and new certs
4. Update clients to trust new cert
5. Remove old cert
Rolling rotation (Kubernetes):
1. cert-manager generates new cert
2. Secret is updated
3. Pods are restarted (rolling update)
4. New pods use new cert
5. Old pods drain and terminateZero-downtime rotation requires the server to accept both old and new certificates during the transition period. In Kubernetes, cert-manager handles this automatically by updating the Secret and triggering pod restarts.
Use short certificate lifetimes (90 days or less) with automated renewal. Long-lived certificates (1-2 years) are harder to revoke and more dangerous if compromised. Let's Encrypt uses 90-day certs by design.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.