Enable HTTPS
With cert-manager, you can have TLS certificates automatically issued by Let's Encrypt and renewed in good time before they expire. The certificates are stored as Kubernetes secrets and used by the Ingress Controller for TLS termination.
Prerequisites
- An Ingress Controller installed; see Installing the Ingress Controller
- A domain whose DNS A record points to the external address of the Ingress Controller
- Helm installed
The DNS entry must point to the external address before the certificate request is made and must be publicly resolvable. Let's Encrypt verifies control of the domain via an HTTP request – if this fails, no certificate will be issued.
You can determine the external address as follows:
kubectl get service -n ingress-nginx ingress-nginx-controller
Install cert-manager
helm repo add jetstack https://charts.jetstack.io
helm repo update
helm install cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--set crds.enabled=true
Check the installation:
kubectl get pods -n cert-manager
All three pods (cert-manager, cert-manager-webhook, cert-manager-cainjector) should have the status Running.
Create a ClusterIssuer
A ClusterIssuer specifies the certification authority from which certificates are obtained.
Test it in the staging environment first
Let's Encrypt significantly limits the number of requests per domain. You should therefore test your configuration against the staging environment first:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
server: https://acme-staging-v02.api.letsencrypt.org/directory
email: ihre-adresse@example.com
privateKeySecretRef:
name: letsencrypt-staging
solvers:
- http01:
ingress:
ingressClassName: nginx
Productive environment
Once the test has been successful, create the production issuer:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: ihre-adresse@example.com
privateKeySecretRef:
name: letsencrypt-prod
solvers:
- http01:
ingress:
ingressClassName: nginx
Apply and check:
kubectl apply -f clusterissuer.yaml
kubectl get clusterissuer
Column READY should read True.
Extending Ingress with TLS
Add the annotation for the issuer and a tls section to your Ingress:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web-ingress
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
ingressClassName: nginx
tls:
- hosts:
- app.example.com
secretName: web-tls
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web
port:
number: 80
How to use:
kubectl apply -f ingress.yaml
The secret specified under secretName is created automatically by cert-manager – you do not need to create it yourself.
Follow the exhibition
# Status des Zertifikats
kubectl get certificate
# Details und Ereignisse
kubectl describe certificate web-tls
# Laufende Anforderungen
kubectl get certificaterequest
kubectl get order
The display usually lasts one to two minutes. Afterwards, ‘True’ appears in column READY of the certificate.
Check the result:
curl -I https://app.example.com
Automatic renewal
cert-manager renews certificates automatically, usually 30 days before they expire. No manual intervention is required as long as the DNS record and ingress remain unchanged.
Troubleshooting
| Symptom | Possible cause |
|---|---|
Certificate remains at READY: False | Check kubectl describe certificate <name> and the associated order and challenge objects |
| Challenge fails | The DNS entry does not point to the external address of the ingress controller or has not yet propagated |
rate limited appears in the events | The quota for Let's Encrypt has been exhausted; use the staging issuer for testing |
| Browser reports an untrusted certificate | The certificate originates from the staging issuer; switch to letsencrypt-prod |
Logs from cert-manager:
kubectl logs -n cert-manager -l app.kubernetes.io/name=cert-manager