cert-manager: Automated TLS Certificate Management in Kubernetes (2026)

cert-manager is the standard Kubernetes add-on for automating TLS certificate issuance and renewal. It integrates with Let's Encrypt, Vault, Venafi, and any ACME-compatible CA to issue certificates as Kubernetes Secret objects — eliminating manual certificate management and expired-cert incidents.

Why cert-manager

Before cert-manager, TLS in Kubernetes meant manually running certbot, copying certificate files into Secrets, and writing cron jobs to renew them before expiry. The failure mode — a forgotten renewal causing an outage — was common.

cert-manager solves this by treating certificates as Kubernetes resources with a controller that continuously reconciles desired state (a Certificate object) with actual state (the TLS Secret). When a cert is 30 days from expiry, cert-manager automatically renews it.

  • Works with any ACME CA (Let's Encrypt, ZeroSSL) and private CAs (Vault, Venafi, self-signed).
  • Issues certs via HTTP-01 (for single domains) or DNS-01 (for wildcard domains).
  • Integrates directly with Ingress controllers via a single annotation.
  • Exposes Prometheus metrics and Kubernetes events for monitoring renewal status.

Installing cert-manager

Install cert-manager using its official Helm chart or the single-file manifest:

# Helm installation (recommended)
helm repo add jetstack https://charts.jetstack.io
helm repo update

helm install cert-manager jetstack/cert-manager \
  --namespace cert-manager \
  --create-namespace \
  --set crds.enabled=true \
  --version v1.14.0

# Verify pods are running
kubectl get pods -n cert-manager
# NAME                                       READY   STATUS
# cert-manager-7d9f4f8c5-xk9pq              1/1     Running
# cert-manager-cainjector-5c7d8f9b6-m2lrp   1/1     Running
# cert-manager-webhook-6b8d7c4f9-n4qzv      1/1     Running
CRDs: The --set crds.enabled=true flag installs the cert-manager Custom Resource Definitions (Certificate, Issuer, ClusterIssuer, etc.) as part of the Helm release, so they are managed and upgraded with the chart.

Issuers and ClusterIssuers

An Issuer is namespace-scoped and can only issue certificates within its namespace. A ClusterIssuer is cluster-scoped and can issue certificates across all namespaces. For most production setups, ClusterIssuer is the right choice.

cert-manager supports two ACME environments from Let's Encrypt:

  • Staging (https://acme-staging-v02.api.letsencrypt.org/directory) — use for testing; issues untrusted certs but has much higher rate limits.
  • Production (https://acme-v02.api.letsencrypt.org/directory) — issues trusted certs; rate-limited to 50 certs per domain per week.
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-account-key
    solvers:
      - http01:
          ingress:
            class: nginx

Apply the ClusterIssuer and verify it is ready:

kubectl apply -f clusterissuer.yaml
kubectl get clusterissuer letsencrypt-prod
# NAME               READY   AGE
# letsencrypt-prod   True    30s

HTTP-01 Challenge

HTTP-01 is the simplest ACME challenge. Let's Encrypt sends an HTTP request to http://<domain>/.well-known/acme-challenge/<token> to verify you control the domain. cert-manager automatically creates a temporary Ingress rule and Pod to serve this challenge.

Requirements for HTTP-01:

  • Your domain's DNS must resolve to the cluster's Ingress IP.
  • Port 80 must be publicly reachable (Let's Encrypt contacts your domain directly).
  • Cannot issue wildcard certificates — use DNS-01 for those.
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: example-com-tls
  namespace: production
spec:
  secretName: example-com-tls-secret
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
  dnsNames:
    - example.com
    - www.example.com

DNS-01 Challenge and Wildcard Certs

DNS-01 proves domain ownership by creating a TXT record in your DNS zone. It supports wildcard certificates (*.example.com) and works even when port 80 is not publicly accessible — making it the right choice for internal services and wildcard certs.

Example using Route53 (AWS):

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-dns01
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: admin@example.com
    privateKeySecretRef:
      name: letsencrypt-dns01-account-key
    solvers:
      - dns01:
          route53:
            region: us-east-1
            accessKeyIDSecretRef:
              name: route53-credentials
              key: access-key-id
            secretAccessKeySecretRef:
              name: route53-credentials
              key: secret-access-key

Wildcard Certificate using DNS-01:

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: wildcard-example-com
  namespace: production
spec:
  secretName: wildcard-example-com-tls
  issuerRef:
    name: letsencrypt-dns01
    kind: ClusterIssuer
  dnsNames:
    - "*.example.com"
    - example.com

Certificate Resource

The Certificate resource is the core cert-manager object. It specifies what cert you want, where to store it, and which issuer to use. cert-manager reconciles this into a Kubernetes TLS Secret:

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: api-tls
  namespace: production
spec:
  secretName: api-tls-secret          # TLS Secret created here
  duration: 2160h                     # 90 days
  renewBefore: 720h                   # Renew 30 days before expiry
  subject:
    organizations:
      - Techoral Inc
  isCA: false
  privateKey:
    algorithm: RSA
    encoding: PKCS1
    size: 2048
  usages:
    - server auth
    - client auth
  dnsNames:
    - api.example.com
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
    group: cert-manager.io

Check certificate status:

kubectl describe certificate api-tls -n production
kubectl get secret api-tls-secret -n production -o yaml

Ingress TLS Annotation

The fastest path to TLS on an Ingress is the cert-manager annotation. cert-manager watches Ingress objects and automatically creates Certificate resources when it sees the annotation:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app
  namespace: production
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
  tls:
    - hosts:
        - app.example.com
      secretName: my-app-tls          # cert-manager populates this Secret
  rules:
    - host: app.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: my-app-service
                port:
                  number: 80
Annotation approach: The Ingress annotation is convenient but gives less control than a dedicated Certificate resource. For fine-grained settings (duration, renewBefore, subject) use a Certificate resource and reference the same Secret in your Ingress tls.secretName.

Automatic Renewal

cert-manager automatically renews certificates before they expire. The renewal window is controlled by renewBefore in the Certificate spec (default: 30 days before expiry). When the renewal window opens, cert-manager re-runs the ACME challenge and updates the Secret with the new certificate — zero downtime, no human intervention.

Monitor renewal status:

# Watch certificate readiness
kubectl get certificates -A -w

# Check events for renewal activity
kubectl describe certificate my-app-tls -n production | grep -A5 Events

# View cert expiry
kubectl get secret my-app-tls -n production -o jsonpath='{.data.tls\.crt}' \
  | base64 -d | openssl x509 -noout -dates

Prometheus metrics from cert-manager expose certmanager_certificate_expiration_timestamp_seconds — use this to alert when a cert is unexpectedly close to expiry (indicating a renewal failure).

Troubleshooting

When a certificate is stuck in a pending or failed state, follow this diagnostic chain:

# Step 1: Check the Certificate status
kubectl describe certificate <name> -n <namespace>
# Look for: Ready: False, Message: ..., Reason: ...

# Step 2: Check the CertificateRequest
kubectl get certificaterequest -n <namespace>
kubectl describe certificaterequest <name> -n <namespace>

# Step 3: Check the Order (ACME challenge object)
kubectl get order -n <namespace>
kubectl describe order <name> -n <namespace>

# Step 4: Check the Challenge
kubectl get challenge -n <namespace>
kubectl describe challenge <name> -n <namespace>

# Step 5: Check cert-manager controller logs
kubectl logs -n cert-manager deploy/cert-manager -f

Common failure causes:

  • HTTP-01 fails — port 80 blocked by firewall, or Ingress not publicly reachable from Let's Encrypt.
  • DNS-01 fails — incorrect IAM permissions for Route53/CloudDNS, or DNS propagation not complete.
  • Rate limited — too many certificate requests to production Let's Encrypt. Test with the staging issuer first.
  • Wrong issuer name — the annotation or Certificate issuerRef does not match the ClusterIssuer name exactly.

FAQ

Does cert-manager work with self-signed internal CAs?
Yes. cert-manager has an SelfSigned issuer type and a CA issuer type that issues certificates from a private root CA stored as a Kubernetes Secret.
Can I use cert-manager with Vault?
Yes. The Vault issuer integrates with HashiCorp Vault's PKI secrets engine. cert-manager authenticates to Vault via Kubernetes service account tokens or AppRole and requests certificates through the Vault PKI API.
Is cert-manager safe for multi-tenant clusters?
Use namespace-scoped Issuer objects for tenant namespaces so tenants cannot issue certificates from a ClusterIssuer they don't own. Reserve ClusterIssuer for platform-team use.
What happens to my app when the cert renews?
cert-manager updates the TLS Secret in place. Ingress controllers and services that watch the Secret (NGINX, Traefik, Istio) pick up the new cert automatically — usually within seconds, with no downtime.
← Kubernetes Hub
Get Weekly Tech Insights

Join 5,000+ engineers getting the best Kubernetes, Java, Cloud and AI articles every week.