Skip to main content
RunBook Academy

KubernetesCXIV · Certificate and TLS OperationsCertificate and TLS operations

ACME issuers — Let's Encrypt and the ACME protocol

Advanced⏱ ~17 minkubectlcert-manager

What you'll learn

  • Configure ACME issuers with Let's Encrypt
  • Use http-01 and dns-01 challenge solvers
  • Issue wildcard certificates
  • Apply the operational discipline of ACME issuers

Prerequisites

Verified against Kubernetes 1.34.x · kubeadm 1.34.x · kubectl 1.34.x · etcd 3.6.x · CoreDNS 1.11.x · containerd 1.7.x / 2.x · 2026-08-16

Not yet marked complete on this device.

ACME is the protocol for automatic certificate issuance; Let’s Encrypt is the most common public ACME server. This lesson walks the protocol, the challenge solvers, wildcards, rate limits, and the discipline.

The ACME protocol

flowchart LR
    A["ACME client: cert-manager"] --> B["ACME server: Let's Encrypt"]
    A -->|1. Register account| B
    A -->|2. Request certificate| B
    B -->|3. Challenge| A
    A -->|4. Solve challenge| B
    B -->|5. Verify challenge| A
    A -->|6. Issue certificate| B

The ACME protocol:

  1. Register. The client registers with the ACME server; the server returns an account URL.
  2. Order. The client requests a certificate for specific domains.
  3. Challenge. The server returns a challenge (http-01 or dns-01).
  4. Solve. The client solves the challenge (proves control of the domain).
  5. Verify. The server verifies the challenge.
  6. Issue. The server issues the certificate.

Let’s Encrypt staging vs production

# Staging (for testing)
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-staging
spec:
  acme:
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    email: ops@example.com
    privateKeySecretRef:
      name: letsencrypt-staging-account
    solvers:
      - http01:
          ingress:
            class: nginx

---
# Production
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: ops@example.com
    privateKeySecretRef:
      name: letsencrypt-prod-account
    solvers:
      - http01:
          ingress:
            class: nginx

The URLs:

  • Staging. acme-staging-v02.api.letsencrypt.org; certificates are not trusted by browsers; no rate limits.
  • Production. acme-v02.api.letsencrypt.org; certificates are trusted; strict rate limits.

Challenge solvers

flowchart LR
    A[Challenge solvers] --> B[http-01]
    B --> B1[HTTP validation]
    B --> B2[Requires Ingress]
    B --> B3[Cannot do wildcard]
    A --> C[dns-01]
    C --> C1[DNS validation]
    C --> C2[Requires DNS provider creds]
    C --> C3[Can do wildcard]

Two solvers:

  • http-01. ACME server requests a specific URL on port 80 of the domain. cert-manager creates an Ingress to serve the URL. Requires HTTP port 80 to reach the cluster.
  • dns-01. ACME server requests a specific TXT record in the domain’s DNS. cert-manager creates the TXT record via the DNS provider’s API. Requires DNS provider credentials. Supports wildcard certificates.

A wildcard certificate

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: wildcard-example
  namespace: prod-app
spec:
  secretName: wildcard-example-tls
  dnsNames:
    - "*.example.com"
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
  duration: 2160h  # 90 days

The wildcard certificate covers *.example.com. The dns-01 solver validates control of example.com.

# dns-01 solver in the ClusterIssuer
solvers:
  - dns01:
      route53:
        region: us-east-1
        accessKeyIDSecretRef:
          name: aws-credentials
          key: access-key-id
        secretAccessKeySecretRef:
          name: aws-credentials
          key: secret-access-key

The Route 53 solver requires AWS credentials in a Secret.

Rate limits

flowchart LR
    A[Let's Encrypt rate limits] --> B[50 certs per domain per week]
    A --> C[5 duplicate certs per week]
    A --> D[5 certs with same SAN set per week]
    B --> E[Test with staging!]
    C --> E
    D --> E

The rate limits:

  • 50 certificates per registered domain per week.
  • 5 duplicate certificates per week.
  • 5 certificates with the same set of names per week.

A misconfigured ClusterIssuer can quickly exhaust the quota. The discipline is to test with staging and to monitor the rate limit.

Quiz

Knowledge check · 4 questions

  1. Q1. Why should a new ACME configuration be tested against Let's Encrypt staging first?

  2. Q2. Exhausting a Let's Encrypt rate limit is resolved by creating a new ACME account.

  3. Q3. Get a wildcard certificate issued after the ACME order stalls on the wrong challenge type.

    A Certificate requests the single name *.example.com from the letsencrypt-prod ClusterIssuer, whose only configured solver is http01 with the nginx ingress class. After an hour, `kubectl get order -n prod-app` shows the order pending and `kubectl describe challenge` shows an http-01 challenge that has never been validated. Route 53 hosts the example.com zone and the team holds an IAM key for it.

  4. Q4. What record does the dns-01 challenge create and at what name, and what are Let's Encrypt's duplicate-certificate and per-registered-domain weekly limits?

Passing score: 75%. Answers are checked in this browser.

The operational discipline

ACME issuers in production rest on five non-negotiable elements:

  • Test with staging. Use Let’s Encrypt staging before production.
  • Use dns-01 for wildcards. http-01 cannot do wildcards.
  • Monitor rate limits. Alert on issuance errors near the limit.
  • Document the solvers. Which solver is used for which certificate.
  • Back up the ACME account key. The Secret stores the account key; losing it means losing the account.

ACME is production certificate management. The discipline is to test, monitor, and document.