August 20, 2020 (updated at: February 02, 2024)
Issue Let's Encrypt certificates for domains in a Kubernetes cluster
We will use cert-manager to issue HTTPS certificates for domains served publicly by a Kubernetes cluster.
The application can be installed via Helm, but it’s recommended to install CRDs (Custom Resource Definitions) separately. That may come in handy if you need to delete cert-manager
without losing already issued certificates. Don’t forget to change the “version” accordingly on all commands.
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.14.1/cert-manager.crds.yaml
Add JetStack charts to your Helm client.
helm repo add jetstack https://charts.jetstack.io --force-update
helm repo update
Install the application.
helm upgrade --install \
cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--version v1.14.1 \
--set ingressShim.defaultIssuerName=letsencrypt-prod \
--set ingressShim.defaultIssuerKind=ClusterIssuer \
--set ingressShim.defaultIssuerGroup=cert-manager.io
To issue actual certificates, you will need a production Issuer or ClusterIssuer. The following yaml defines a ClusterIssuer and assumes that you have a nginx
ingress controller. If it suit your needs, apply it to your cluster.
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
# The ACME server URL
server: https://acme-v02.api.letsencrypt.org/directory
# Email address used for ACME registration
email: <your_email>
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: letsencrypt-prod
# Enable the HTTP-01 challenge provider
solvers:
- http01:
ingress:
ingressClassName: nginx
Verify if your set up is working.
$ kubectl get clusterissuers -A
NAME READY AGE
letsencrypt-prod True 30m
The cert-manager
stack will act upon ingresses that comply with a couple of conditions to generate HTTPS certificates. The following example illustrates that. Take special note of the annotations and the “secretName” property under “tls”.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
kubernetes.io/tls-acme: "true"
name: nginx-ingress
namespace: ingress-testing
spec:
rules:
- host: <public_URL>
http:
paths:
- backend:
serviceName: <service_name>
servicePort: 80
tls:
- hosts:
- <public_URL>
secretName: <secret_name_of_your_choosing>
Further reading
Official documentation on the installation process