Skip to main content
Automate TLS certificate management using cert-manager, which integrates with Let’s Encrypt to provide automatic certificate issuance and renewal.

Prerequisites

Before setting up cert-manager, ensure you have:
  • Helm installed (installation guide)
  • A Kubernetes cluster with Ingress controller
  • A domain name with DNS configured

Install cert-manager

Install cert-manager using Helm:
helm repo add jetstack https://charts.jetstack.io
helm repo update
helm install cert-manager jetstack/cert-manager \
  --namespace cert-manager \
  --create-namespace \
  --set installCRDs=true
Refer to the cert-manager Helm installation guide for detailed options.

Configure ClusterIssuer

Create a ClusterIssuer to handle certificate requests with Let’s Encrypt:
issuer.yml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    email: [email protected]
    server: https://acme-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      name: letsencrypt-prod
    solvers:
    - http01:
        ingress:
          class: nginx
Apply the ClusterIssuer:
kubectl apply -f issuer.yml
Verify the ClusterIssuer was created:
kubectl get clusterissuer
kubectl describe clusterissuer letsencrypt-prod
Replace [email protected] with your actual email address. Let’s Encrypt uses this for certificate expiration notifications.

Certificate Management

Option 1: Standalone Certificate Resource

Create a standalone Certificate resource:
certificate.yml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: exchange-cert
  namespace: default
spec:
  secretName: exchange-tls
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
  commonName: exchange.example.com
  dnsNames:
    - exchange.example.com
Apply the certificate:
kubectl apply -f certificate.yml

Option 2: Automatic Certificate via Ingress Annotations

Define certificates directly in your Ingress resource (recommended):
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-ingress
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - app.example.com
    secretName: app-tls
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: app-service
            port:
              number: 80
Using Ingress annotations is preferred as it keeps certificate configuration alongside routing rules.

Verify Certificates

Check certificate status:
kubectl get certificate
kubectl describe certificate exchange-cert
Inspect the generated TLS secret:
kubectl get secret exchange-tls -n default -o yaml
View certificate details:
kubectl get secret exchange-tls -n default -o jsonpath='{.data.tls\.crt}' | base64 --decode | openssl x509 -text -noout

Troubleshooting TLS Issues

Certificate Not Issued

  1. Check certificate status:
    kubectl describe certificate <cert-name>
    
  2. Check certificate request:
    kubectl get certificaterequest
    kubectl describe certificaterequest <request-name>
    
  3. Check ACME challenge:
    kubectl get challenges
    kubectl describe challenge <challenge-name>
    

Common Issues

DNS not configured: Ensure your domain points to your cluster’s Ingress IP
kubectl get ingress
nslookup your-domain.com
HTTP-01 challenge failing: Verify that port 80 is accessible and not redirected before certificate issuance Rate limits: Let’s Encrypt has rate limits. Use staging server for testing:
server: https://acme-staging-v02.api.letsencrypt.org/directory

Delete and Recreate Certificate

If you need to start fresh:
kubectl delete certificate exchange-cert
kubectl delete secret exchange-tls
Then reapply your certificate configuration.

Additional Resources

cert-manager Video Tutorial

Step-by-step guide for setting up cert-manager in Kubernetes
When following external tutorials, use the issuer configuration provided in this documentation to match your cluster setup.

Build docs developers (and LLMs) love