Automate Certificate Rotation

Khimananda Oli 9 min read Virtualization
Automate Certificate Rotation

By Khimananda Oli | Last reviewed: August 2026

Expired TLS certificates remain a top cause of avoidable production outages, yet most teams still rely on calendar reminders or fragile cron scripts to manage renewals. When you automate certificate rotation, you shift from reactive firefighting to a declarative, self-healing security posture that satisfies both uptime SLAs and SOC 2 auditors. This guide covers the exact architecture, tooling, and configuration patterns I use to keep thousands of endpoints valid without human intervention.

cert-managerController PodACME ServerLet's Encrypt / CAK8s Secrettls.crt / tls.keyDNS ProviderRoute53 / Cloudflare1. CSR + Challenge2. Signed Cert3. DNS-01 Verify
Automate certificate rotation architecture: cert-manager orchestrates ACME challenges and stores renewed TLS assets as Kubernetes Secrets.

How do you automate certificate rotation with cert-manager?

Cert-manager has become the de facto standard for Kubernetes-native TLS automation because it treats certificates as first-class API resources rather than external artifacts. The core loop is simple: you define a Certificate resource, and the controller reconciles the desired state against the actual secret, triggering renewal when the expiry window approaches. For teams managing infrastructure across Nepal and global regions, this declarative approach eliminates timezone coordination issues during manual renewal windows.

Install and configure the ClusterIssuer

Before requesting any certificates, you must define an issuer that knows how to speak ACME. I recommend using DNS-01 challenges exclusively in production; HTTP-01 requires open ingress paths and fails for internal services or wildcard domains. The following configuration uses AWS Route53 for DNS validation, but the pattern applies identically to Cloudflare, Azure DNS, or Google Cloud DNS.

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: [email protected]
    privateKeySecretRef:
      name: letsencrypt-prod-account-key
    solvers:
    - dns01:
        route53:
          region: us-east-1
          hostedZoneID: Z1234567890ABC
          accessKeyIDSecretRef:
            name: route53-credentials
            key: access-key-id
          secretAccessKeySecretRef:
            name: route53-credentials
            key: secret-access-key

A common mistake here is granting overly broad IAM permissions for DNS updates. Follow least-privilege principles by scoping the Route53 policy to only the specific hosted zone required. If you are integrating this with broader observability, ensure your Prometheus metrics monitoring fundamentals include cert-manager’s renewal success and failure counters so expired certs trigger alerts before users notice.

Define the Certificate resource with renewal windows

The default renewal window in cert-manager is one-third of the certificate lifetime. For 90-day Let’s Encrypt certs, this means renewal attempts start at day 60. In high-compliance environments, I often tighten this to 30 days remaining to allow ample retry time for transient ACME failures. Always specify renewBefore explicitly rather than relying on defaults.

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: api-gateway-tls
  namespace: production
spec:
  secretName: api-gateway-tls-secret
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
  dnsNames:
  - api.example.com
  - "*.internal.example.com"
  renewBefore: 720h   # 30 days
  duration: 2160h     # 90 days
  privateKey:
    algorithm: ECDSA
    size: 256

Using ECDSA P-256 keys instead of RSA-2048 reduces TLS handshake latency by roughly 40% on modern hardware while maintaining equivalent security strength. Most browsers and clients have supported ECDSA since 2015; there is no practical compatibility reason to default to RSA in 2026 unless you are supporting legacy embedded devices.

What is the difference between ACME DNS-01 and HTTP-01 challenges?

Choosing the right challenge type determines whether your automation actually works for all your services. HTTP-01 validates domain ownership by serving a token over port 80, which means the domain must be publicly routable and your ingress must be configured to pass the challenge path through. DNS-01 validates by creating a TXT record, which works for wildcards, internal hostnames, and services behind strict firewalls.

CriteriaHTTP-01DNS-01
Wildcard supportNoYes
Internal/private domainsNoYes
Requires public ingressYesNo
DNS provider API accessNot neededRequired
Propagation delayNegligible30–120 seconds typical
Security exposureToken visible on port 80TXT record only

In practice, I standardize on DNS-01 for every environment. The marginal complexity of configuring DNS provider credentials pays for itself immediately when you need to rotate a wildcard cert or add an internal service endpoint. HTTP-01 should be reserved only for quick local testing or single-domain setups where DNS API access is genuinely unavailable.

cert-managerACME CAIngress / LBDNS ProviderOrderChallenge TokenHTTP-01 PathServe TokenDNS-01 TXTCreate _acme-challengePropagation WaitValidate ✓Signed Cert
ACME challenge comparison: HTTP-01 requires public ingress path, while DNS-01 uses TXT records enabling wildcard and internal certificate automation.

How do you handle zero-downtime certificate reloading?

Renewing the certificate is only half the problem; your application or ingress controller must actually load the new secret without dropping active connections. Many teams successfully automate certificate rotation only to discover their Nginx pods are still serving the old cert three days after renewal because no reload signal was sent.

Ingress controller integration

Modern ingress controllers like NGINX Ingress Controller, Traefik, and Cilium Gateway API watch Kubernetes Secrets natively and hot-reload TLS configurations when the secret content changes. Cert-manager updates the secret in place, and the ingress controller detects the change via the Kubernetes watch API. No pod restart or annotation hack is required. Verify this behavior in your staging environment first by checking the ingress controller logs for "TLS secret updated" messages after a forced renewal.

Application-level reloading for direct TLS

If your application terminates TLS directly (common with Go, Rust, or Java services bypassing the ingress), you need an explicit reload mechanism. The most reliable pattern is to watch the certificate file or secret mount for changes and trigger a graceful listener reset. For applications that cannot self-watch, use a sidecar container with stakater/reloader or a shared volume watcher that sends SIGHUP to the main process.

# Example: Force cert-manager to renew immediately for testing
kubectl annotate certificate api-gateway-tls \
  cert-manager.io/renew=true --overwrite

# Watch ingress controller logs for reload confirmation
kubectl logs -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx \
  --tail=50 | grep -i "tls\|secret\|reload"

Never rely on pod restarts as your primary reload strategy. Restarting pods causes connection resets and violates zero-downtime requirements. If your current setup requires restarts, prioritize migrating to an ingress controller with native secret watching or implement proper signal handling in your application. For deeper guidance on secure secret delivery, see Kubernetes secrets management done right.

How do you monitor certificate expiry and rotation health?

Automation without observability is just silent failure waiting to happen. You must treat certificate rotation as a critical system component with its own SLIs and alerts. I track three metrics as non-negotiable: days until expiry per certificate, renewal attempt count with error labels, and last successful renewal timestamp. These map directly to the four golden signals of monitoring framework applied to PKI operations.

  • Expiry alerting: Fire a warning at 30 days remaining and critical at 14 days. This gives your team buffer to investigate ACME failures before user impact.
  • Renewal failure rate: Alert if more than 5% of renewal attempts fail within a 24-hour window. Transient network errors are normal; sustained failures indicate misconfigured issuers or exhausted rate limits.
  • Staleness detection: Alert if any managed certificate has not been successfully renewed within its expected cycle plus a grace period. Catches silent controller crashes or orphaned Certificate resources.

Export these metrics from cert-manager’s built-in Prometheus endpoint. Do not build custom scrapers or parse logs for expiry dates. The official metrics are stable, well-documented, and cover edge cases your homegrown solution will miss. Pair this with a Grafana dashboard that overlays renewal events against traffic graphs to correlate certificate operations with user-facing errors.

cert-manager/metrics :8080certmanager_certificate_expiration_secondsPrometheusScrape 15sAlert RulesAlertmanager<30d Warning<14d CriticalGrafanaPKI DashboardExpiry + Renewal OverlayPagerDuty /Slack / OpsGenieOn-call Notification
Certificate rotation observability: cert-manager exports expiry metrics to Prometheus, triggering tiered alerts and dashboards before certificates expire.

When should you use cloud-native certificate services instead?

Cert-manager is excellent for Kubernetes-centric workloads, but it is not always the right tool. If your entire stack lives within a single cloud provider and you do not need cross-cloud portability, native certificate managers reduce operational overhead significantly. AWS Certificate Manager (ACM), Google Cloud Certificate Manager, and Azure App Service Certificates handle issuance, renewal, and attachment to load balancers or CDNs without exposing private keys to your cluster at all.

The trade-off is vendor lock-in and reduced flexibility. Cloud-managed certificates typically cannot be exported for use outside the provider’s ecosystem. You cannot use them for mutual TLS between microservices inside Kubernetes, for signing JWTs, or for databases that require client certificates. My rule of thumb: use cloud-native services for public-facing ingress and CDN edges where key export is unnecessary, and use cert-manager for everything else including internal mTLS, database encryption, and multi-cloud deployments. This hybrid approach gives you the simplicity of managed services where possible while retaining full control where it matters.

For teams operating under SOC 2 or ISO 27001, document this decision matrix explicitly in your compliance evidence. Auditors want to see that you have evaluated alternatives and chosen based on risk, not convenience. Automated evidence collection from your IaC repositories and monitoring systems makes this straightforward during audit cycles.

Start Automating Certificate Rotation Today

Manual certificate management is technical debt that compounds silently until it causes a customer-facing outage. The tools and patterns described here are battle-tested across production environments ranging from Nepali fintech startups to multinational SaaS platforms. Pick one issuer, deploy cert-manager or your cloud provider’s equivalent, configure monitoring before you configure renewal, and validate the full cycle in staging. If your team needs help designing a compliant, zero-downtime PKI automation strategy, reach out to discuss your infrastructure.

Frequently Asked Questions

Certbot remains the standard for Let's Encrypt automation, while cert-manager is preferred for Kubernetes clusters. Both support ACME v2 and integrate with major cloud providers for DNS validation without manual intervention.

Schedule renewal checks daily but expect actual rotation thirty days before expiry. This buffer prevents outages from transient API failures or DNS propagation delays during the automated renewal process.

Yes, using DNS-01 challenges via ACME. You must configure API credentials for your DNS provider to allow the automation tool to create and delete TXT records dynamically during validation.

No. Modern web servers like Nginx and Caddy support binary reloads that apply new certificates without dropping active connections, ensuring zero-downtime rotation during automated renewal cycles.

Yes, if using Let's Encrypt or ZeroSSL via ACME. Commercial CAs charge fees, but the automation logic itself using open-source tools like acme.sh or lego incurs no licensing costs.

Use the staging environment flag in your ACME client to avoid rate limits. Verify the full renewal and reload cycle works correctly before switching to production endpoints.

Configure alerting on renewal script exit codes and certificate expiry dates. Relying solely on automation without monitoring risks unexpected outages when API changes or credential expirations break the pipeline.

Yes. Use the acme_certificate module with a central ACME account. Distribute renewed certificates via copy or synchronize modules and trigger handler-based service reloads atomically across the fleet.

It watches Certificate resources and renews them automatically via ACME. Renewed secrets are updated in-place, and ingress controllers detect changes to serve new TLS material immediately.

Most reverse proxies reload gracefully, but backend apps reading certs directly may need restarts. Use file watchers or signal handlers to detect new certificate files and reload TLS contexts dynamically.

Restrict to read/write access for certificate directories and capability to reload the web server. Never grant root unless necessary; use sudoers rules limited to specific systemctl or nginx commands.

ACM handles public certificates natively. For private CA or imported certs, use EventBridge rules triggering Lambda functions to renew and reimport certificates before expiration dates.

ACME clients occasionally deprecate old config formats or authentication methods. Check release notes for breaking changes, validate your account key, and ensure DNS provider plugins match current API versions.

Never. Store only configuration templates and renewal scripts. Certificates contain sensitive private keys that must remain on secure infrastructure or in encrypted secret managers, never in Git repositories.

Run openssl s_client against your domain post-reload to confirm the new certificate chain serves correctly and matches the expected expiry date returned by the automation tool.