Skip to main content

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
Warnung

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

SymptomPossible cause
Certificate remains at READY: FalseCheck kubectl describe certificate <name> and the associated order and challenge objects
Challenge failsThe DNS entry does not point to the external address of the ingress controller or has not yet propagated
rate limited appears in the eventsThe quota for Let's Encrypt has been exhausted; use the staging issuer for testing
Browser reports an untrusted certificateThe 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