Set up a Let's Encrypt ClusterIssuer
A Let's Encrypt ClusterIssuer enables cert-manager to obtain free, trusted certificates for every ingress in the cluster. Let's Encrypt is a free certificate authority. cert-manager communicates with it over a protocol called ACME, which proves you control a domain before Let's Encrypt signs a certificate for it. You create the issuer once, annotate an Ingress, and cert-manager handles the rest. This assumes cert-manager is installed .
Start on staging#
Let's Encrypt rate-limits how many certificates you can request for a domain, and a misconfigured issuer can exhaust that limit quickly. Use the staging endpoint until the flow works end to end, then switch to production. Staging certificates are not trusted by browsers, which is precisely why they are safe to iterate against.
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
server: https://acme-staging-v02.api.letsencrypt.org/directory
email: you@example.com
privateKeySecretRef:
name: letsencrypt-staging-account
solvers:
- http01:
ingress:
ingressClassName: nginx
Switch the server to https://acme-v02.api.letsencrypt.org/directory and rename the issuer to letsencrypt-prod once staging issues certificates cleanly.
Prove domain control: HTTP-01 or DNS-01#
Before Let's Encrypt signs a certificate, ACME requires cert-manager to prove you control the domain. It runs one of two challenge types, and the one you choose determines whether you can issue wildcards.
HTTP-01 proves control by serving a token over HTTP through your ingress. It works for any host that already points to your load balancer and requires no DNS credentials. cert-manager adds a temporary ingress path for the challenge and removes it afterward. This is the http01 solver in the staging issuer above.
solvers:
- http01:
ingress:
ingressClassName: nginx
HTTP-01 cannot issue wildcard certificates.
DNS-01 proves control by writing a TXT record to your zone, so it works even when the host is not reachable over HTTP, and it is the only challenge that can issue a wildcard (*.example.com). Provide cert-manager with a scoped API token for your DNS provider:
solvers:
- dns01:
cloudflare:
apiTokenSecretRef:
name: cloudflare-api-token
key: token
To avoid granting cert-manager access to your entire zone, delegate the _acme-challenge record to a separate zone with a CNAME and set cnameStrategy: Follow on the solver. For wildcard and multi-host certificates and the CNAME delegation setup, see Multi-domain and wildcard certificates .
Issue a certificate#
Point an Ingress at the issuer with an annotation, and name the Secret that cert-manager should populate:
metadata:
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
tls:
- hosts: [app.example.com]
secretName: app-example-com-tls
Verify#
cert-manager creates a Certificate object and, once the challenge passes, writes the Secret:
$ kubectl get certificate
NAME READY SECRET
app-example-com-tls True app-example-com-tls
$ kubectl describe certificate app-example-com-tls
READY: True means the certificate is issued and the ingress can serve HTTPS. If it remains False, the events on the Certificate and the Order/Challenge objects show which step failed, usually a DNS record that has not yet propagated or a challenge that could not reach the ingress.
A certificate at the edge is one layer of the cluster's security model . Once the Secret exists, the ingress uses it to terminate TLS , and cert-manager renews it before it expires without requiring you to track the date.