Replication Blueprint: Follow these 4 steps on any Kubernetes cluster (K3s, MicroK8s, EKS, AKS, GKE) to achieve automated, zero-cost TLS certificate rotation using cert-manager and Let's Encrypt.
1
Deploy cert-manager Controller

Install the official cert-manager Custom Resource Definitions (CRDs) and controller. This adds native Kubernetes resources like ClusterIssuer, Certificate, and Challenge to your cluster.

BASH · Install cert-manager via Helm / Manifest
# Install cert-manager with CustomResourceDefinitions (CRDs)
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.14.4/cert-manager.yaml

# Verify that cert-manager pods are Running
kubectl get pods -n cert-manager
2
Configure ACME ClusterIssuer (Let's Encrypt Production)

Create a cluster-wide ClusterIssuer configuring the ACME HTTP-01 solver. Traefik (or ingress-nginx) will automatically answer ACME HTTP challenges under /.well-known/acme-challenge/.

YAML · cluster-issuer.yml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: your-sre-team@example.com
    privateKeySecretRef:
      name: letsencrypt-prod-account-key
    solvers:
    - http01:
        ingress:
          class: traefik   # or 'nginx' depending on your ingress controller
3
Annotate Ingress for Zero-Touch Auto-Issuance & Renewal

Add the annotation cert-manager.io/cluster-issuer: letsencrypt-prod to your Ingress resource. When applied, cert-manager automatically issues the certificate, stores it in secretName, and automatically renews it 30 days before the 90-day expiry.

YAML · ingress-tls.yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: codexrelic-web-ingress
  namespace: default
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
    traefik.ingress.kubernetes.io/router.entrypoints: websecure
    traefik.ingress.kubernetes.io/router.tls: "true"
spec:
  ingressClassName: traefik
  tls:
  - hosts:
    - codexrelic.com
    - www.codexrelic.com
    secretName: codexrelic-tls-secret   # cert-manager manages and updates this secret
  rules:
  - host: codexrelic.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-service
            port:
              number: 80
4
Automate Daily CI/CD Certificate Audits (Azure DevOps Pipeline)

Set up a scheduled cron pipeline in Azure DevOps or GitHub Actions that connects via SSH/kubectl and validates that all certificates are in READY=True state across all namespaces, failing the build and alerting the on-call SRE if any renewal stalls.

YAML · azure-pipelines-ssl-check.yml
trigger: none
schedules:
- cron: "0 0 * * *"   # Runs daily at midnight UTC
  displayName: Daily SSL Expiry & Renewal Check
  branches:
    include:
    - main
  always: true

jobs:
- job: SSL_Health_Audit
  pool:
    vmImage: 'ubuntu-latest'
  steps:
  - task: SSH@0
    inputs:
      sshEndpoint: 'k3s-control-plane'
      runOptions: 'inline'
      inline: |
        echo "=== Auditing Kubernetes SSL Certificates ==="
        kubectl get certificates --all-namespaces -o wide
        
        # POSIX verification: Ensure 100% of certs have READY=True
        INVALID_CERTS=$(kubectl get certificates --all-namespaces --no-headers | awk '$3 != "True" {print $1 "/" $2 " (Status: " $3 ")"}')
        
        if [ -n "$INVALID_CERTS" ]; then
          echo "##vso[task.logissue type=error]Certificates not READY: $INVALID_CERTS"
          exit 1
        fi
        echo "✅ All Kubernetes SSL Certificates are Valid and Auto-Managed!"
Enterprise CA Extension: If your organization uses commercial SSL certificates issued by providers like DigiCert, Sectigo, ZeroSSL, Cloudflare, or GoDaddy, you can easily adapt this architecture using three standard production patterns.
A
Pattern A: ACME Automation with Commercial Providers (EAB)

Major commercial CAs (Sectigo, DigiCert CertCentral, ZeroSSL, Entrust) support the ACME protocol via External Account Binding (EAB). You retain fully automated rotation while using your corporate enterprise CA account.

YAML · commercial-eab-issuer.yml (DigiCert / Sectigo / ZeroSSL)
# 1. Store your CA provider's EAB HMAC Key in a Secret
apiVersion: v1
kind: Secret
metadata:
  name: ca-eab-secret
  namespace: cert-manager
type: Opaque
stringData:
  secret: "YOUR_COMMERCIAL_CA_HMAC_KEY"
---
# 2. Configure ClusterIssuer with External Account Binding (EAB)
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: commercial-ca-issuer
spec:
  acme:
    server: https://acme.zerossl.com/v2/DV90 # Or DigiCert / Sectigo ACME URL
    email: security-ops@enterprise.com
    externalAccountBinding:
      keyID: "YOUR_EAB_KEY_ID_FROM_CA_PORTAL"
      keySecretRef:
        name: ca-eab-secret
        key: secret
    privateKeySecretRef:
      name: commercial-account-key
    solvers:
    - http01:
        ingress:
          class: traefik
B
Pattern B: Applying Pre-Issued Commercial TLS Bundles (.crt & .key)

If you purchased a 1-year or multi-year Wildcard SSL certificate (e.g., *.yourcompany.com) from GoDaddy, Namecheap, or Comodo as flat certificate files, you can bind it directly to Kubernetes as a native TLS Secret.

BASH · Create Kubernetes TLS Secret
# Create standard Kubernetes TLS secret with Certificate Bundle (cert + intermediate CA) & Private Key
kubectl create secret tls enterprise-wildcard-tls \
  --cert=/path/to/fullchain_bundle.crt \
  --key=/path/to/private.key \
  --namespace=prod

# Reference the secret directly in your Ingress manifest:
# spec:
#   tls:
#   - hosts:
#     - app.yourcompany.com
#     secretName: enterprise-wildcard-tls
C
Pattern C: Enterprise Cloud Vault Sync (External Secrets Operator / CSI)

For enterprise multi-cloud setups, store commercial certificates in Azure Key Vault, AWS Secrets Manager, or HashiCorp Vault and use the External Secrets Operator (ESO) to auto-sync TLS secrets directly into Kubernetes namespaces whenever updated in the vault.

YAML · external-secrets-tls-sync.yml
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: corporate-wildcard-tls
  namespace: prod
spec:
  refreshInterval: 1h   # Automatically pulls updated cert from Cloud Vault
  secretStoreRef:
    name: azure-keyvault-store
    kind: ClusterSecretStore
  target:
    name: corporate-wildcard-tls-secret
    template:
      type: kubernetes.io/tls
      data:
        tls.crt: "{{ .certificate }}"
        tls.key: "{{ .privatekey }}"
  data:
  - secretKey: certificate
    remoteRef:
      key: CorporateWildcardCert
  - secretKey: privatekey
    remoteRef:
      key: CorporateWildcardKey