Cloud Native 18 min read

Automate Kubernetes TLS Certificates with cert‑manager, External DNS, and NGINX Ingress

This guide shows how to replace the error‑prone manual TLS workflow in Kubernetes by integrating cert‑manager, External DNS and the NGINX Ingress Controller to automatically obtain, validate and renew Let’s Encrypt certificates, reducing cost and operational overhead.

DevOps Coach
DevOps Coach
DevOps Coach
Automate Kubernetes TLS Certificates with cert‑manager, External DNS, and NGINX Ingress

Introduction

Managing TLS certificates for Kubernetes applications has traditionally been a manual, error‑prone process that discourages developers from enabling proper encryption. This guide walks through building a fully automated certificate management pipeline using cert‑manager , External DNS , and the NGINX Ingress Controller , producing a production‑ready, secure setup.

Why Automate TLS?

The classic certificate lifecycle involves generating a CSR, submitting it to a CA, paying fees, downloading the certificate, configuring the web server, and remembering to renew before expiration. This manual flow leads to service outages, security gaps, high operational costs, and expensive certificates.

Solution Architecture Overview

The automated solution consists of four key components:

External DNS – watches Ingress resources and automatically creates DNS records with your provider.

NGINX Ingress Controller – provides a single cloud load balancer that routes traffic to multiple services.

cert‑manager – requests, validates and renews TLS certificates from Let’s Encrypt (or other CAs).

Let’s Encrypt – a free, automated CA that issues trusted certificates.

Component Interaction

DNS Registration : External DNS monitors Ingress changes and creates the appropriate DNS A record.

Traffic Routing : NGINX Ingress routes incoming traffic based on host names.

Certificate Issuance : cert‑manager detects the TLS requirement and requests a certificate.

Validation : Let’s Encrypt validates domain ownership via a DNS‑01 challenge.

Deployment : The issued certificate is stored in a Kubernetes Secret and automatically applied to the service.

Cost Benefits

Using a single Ingress load balancer instead of one per service reduces monthly load‑balancer costs from $30 to $10 (a 67% saving).

Step‑by‑Step Implementation

Prerequisites

A managed Kubernetes cluster (DigitalOcean, EKS, GKE, or AKS).

kubectl configured for the cluster.

A domain you control.

API access to your DNS provider.

Step 1 – Install External DNS

Example for DigitalOcean:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: external-dns
  namespace: myapp-tls
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: external-dns
rules:
- apiGroups: [""]
  resources: ["services","endpoints","pods"]
  verbs: ["get","watch","list"]
- apiGroups: ["extensions","networking.k8s.io"]
  resources: ["ingresses"]
  verbs: ["get","watch","list"]
- apiGroups: [""]
  resources: ["nodes"]
  verbs: ["get","watch","list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: external-dns-viewer
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: external-dns
subjects:
- kind: ServiceAccount
  name: external-dns
  namespace: myapp-tls
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: external-dns
  namespace: myapp-tls
spec:
  selector:
    matchLabels:
      app: external-dns
  template:
    metadata:
      labels:
        app: external-dns
    spec:
      serviceAccountName: external-dns
      containers:
      - name: external-dns
        image: k8s.gcr.io/external-dns/external-dns:v0.11.0
        args:
        - --source=ingress
        - --domain-filter=yourdomain.com
        - --provider=digitalocean
        - --log-level=debug
        env:
        - name: DO_TOKEN
          value: "your-digitalocean-api-token"

Key flags: --source=ingress – watch Ingress resources. --domain-filter – limit DNS updates to your domain. --log-level=debug – enable detailed logs for troubleshooting.

Step 2 – Deploy NGINX Ingress Controller

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.2.0/deploy/static/provider/cloud/deploy.yaml

The command creates the ingress-nginx namespace, the controller pods, a LoadBalancer service, and the necessary RBAC permissions.

Step 3 – Install cert‑manager

kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.8.0/cert-manager.yaml

This creates the cert-manager namespace, CRDs for Certificates, Issuers, Challenges, and three controllers (cert‑manager, cainjector, webhook).

Step 4 – Deploy a Sample Application

# Create two nginx pods
kubectl run nginx01 --image=nginx --port=80
kubectl run nginx02 --image=nginx --port=80
# Label the pods
kubectl label pod nginx01 nginx02 app=myapp-tls
# Expose as a ClusterIP service on port 443
kubectl create service clusterip myapp-tls --tcp=443:80

Step 5 – Configure a ClusterIssuer (Staging)

apiVersion: v1
kind: Secret
metadata:
  name: digitalocean-dns
  namespace: cert-manager
stringData:
  access-token: "your-digitalocean-api-token"
---
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-staging
spec:
  acme:
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    email: [email protected]
    privateKeySecretRef:
      name: cert-manager-letsencrypt-account-staging-key
    solvers:
    - dns01:
        digitalocean:
          tokenSecretRef:
            name: digitalocean-dns
            key: access-token

Important: When using a ClusterIssuer, the secret must reside in the cert-manager namespace.

Step 6 – Create the Ingress Resource

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api-example-com
  namespace: myapp-tls
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-staging"
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - api.example.com
    secretName: cert-api-example-com
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: myapp-tls
            port:
              number: 443

Key annotations: cert-manager.io/cluster-issuer – tells cert‑manager which issuer to use. ingressClassName – selects the NGINX Ingress controller.

Monitoring & Troubleshooting

Check certificate status with:

kubectl get certificate -n myapp-tls
kubectl describe certificate -n myapp-tls
kubectl describe certificaterequest -n myapp-tls
kubectl describe order -n myapp-tls
kubectl describe challenge -n myapp-tls

Common Issues

Secret not found : Ensure the secret lives in the cert-manager namespace when using a ClusterIssuer.

DNS‑01 timeout : Verify the API token has proper permissions and the domain is correctly configured.

IngressClass conflict : Use either the annotation or the ingressClassName field, not both.

Production Considerations

Switch to Production Issuer

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: cert-manager-letsencrypt-account-prod-key
    solvers:
    - dns01:
        digitalocean:
          tokenSecretRef:
            name: digitalocean-dns
            key: access-token

Be aware of Let’s Encrypt rate limits; test thoroughly in the staging environment first.

Security Best Practices

Use a dedicated secret‑management solution (e.g., HashiCorp Vault) for API tokens.

Apply least‑privilege RBAC policies.

Enforce network policies between components.

Set up alerts for certificate expiry or renewal failures.

High‑Availability Setup

Run multiple replicas of the Ingress controller.

Apply anti‑affinity rules to spread pods across nodes.

Define appropriate CPU/memory requests and limits.

Configure readiness and liveness probes.

Real‑World Use Cases

E‑commerce Platform

Automated TLS for services such as store.company.com, api.company.com, admin.company.com, and payments.company.com eliminated downtime, cut load‑balancer costs by ~70%, and boosted developer productivity.

SaaS Multi‑Tenant Application

Each customer sub‑domain (e.g., customer1.saas-platform.com) receives a Let’s Encrypt certificate automatically, with zero manual intervention.

Performance & Scalability

Typical resource consumption per component:

External DNS: 50 mCPU, 50 Mi memory

NGINX Ingress Controller: 100 mCPU, 90 Mi memory

cert‑manager controller: 10 mCPU, 32 Mi memory per pod

The architecture scales to thousands of DNS records, hundreds of services behind a single load balancer, and hundreds of certificates managed by cert‑manager.

Advanced Features

Multiple DNS Providers

# Support both DigitalOcean and Cloudflare
args:
  - --source=ingress
  - --provider=digitalocean
  - --provider=cloudflare

Custom Certificate Authorities

cert‑manager can integrate with Let’s Encrypt, HashiCorp Vault, Venafi, self‑signed CAs, or internal corporate CAs.

Webhook DNS‑01 Solver

solvers:
- dns01:
    webhook:
      groupName: acme.example.com
      solverName: custom-solver

Conclusion

By combining cert‑manager, External DNS, and the NGINX Ingress Controller you can transform Kubernetes TLS management from a fragile manual process into a reliable, automated system that improves security, cuts costs, and frees developers to focus on application logic.

Key Benefits

Security : Automatic TLS for all services.

Cost Efficiency : Up to 67% reduction in load‑balancer expenses.

Operational Excellence : Zero manual certificate handling.

Reliability : Automatic renewal prevents outages.

Developer Productivity : Less time spent on infra tasks.

Next Steps

Start with the staging environment to become familiar with each component.

Test certificate issuance on a non‑critical domain.

Gradually migrate production workloads.

Implement monitoring and alerting for certificate health.

Consider extending the setup to multiple clusters or more advanced use cases.

cloud-nativeAutomationKubernetesTLSNGINX Ingresscert-managerExternal DNS
DevOps Coach
Written by

DevOps Coach

Master DevOps precisely and progressively.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.