SSL/TLS certificates have long become a standard for websites facing the public internet. Ever since the release of ACME certificate providers like LetsEncrypt and ZeroSSL, setting up website traffic encryption has become an easy and free (in some cases even fully automatic) process. While Kubernetes does not include a way to use these services out of the box, the cert-manager adds this missing feature to ingress resources.
Installing cert-manager
The tool of choice for automated certificate management in Kubernetes is cert-manager. While cert-manager can do much more than just automate certificates for ingress resources, that task remains one of it's most popular use cases. You can install cert-manager with kubectl
:
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.2/cert-manager.yaml
This will create several resources in the cert-manager namespace. You can view their pod status with
kubectl get pods --namespace cert-manager --watch
Once all pods are ready, cert-manager is operational.
Creating issuers
In order to automatically retrieve certificates, cert-manager needs to know how to communicate with ACME service providers. This is done by configuring ClusterIssuer
resources:
staging.yml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
# Replace this with your own email
email: user@example.com
server: https://acme-staging-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: le-staging-issuer-account-key
solvers:
- http01:
ingress:
ingressClassName: nginx
This creates a staging issuer for LetsEncrypt's public staging endpoint. This serves as a way to test if certificate retrieval would success, without hitting the API rate limits of the real LetsEndcrypt API. Remember to replace the email
field with your own email address or the issuer will not be able to retrieve certificates. LetsEncrypt will also use this email to contact you about expiring certificates and account-related issues.
To receive real, valid certificates, you will need a second issuer used in production:
prod.yml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
# Replace this with your own email
email: user@example.com
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: le-prod-issuer-account-key
solvers:
- http01:
ingress:
ingressClassName: nginx
You can now receive testing certificates using letsencrypt-staging
and official ones with letsencrypt-prod
.
Protecting an ingress with SSL
In order to add automated SSL certificates to an ingress, you simply deploy it with some slight adjustments:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
name: sample-web
spec:
tls:
- hosts:
- sample-web.com
secretName: sample-web-ingress-cert
ingressClassName: nginx
rules:
- host: sample-web.com
http:
paths:
- pathType: Prefix
path: /
backend:
service:
name: sample-web-deployment
port:
number: 80
This is a simple ingress forwarding traffic for the internal sample-web-deployment on the domain sample-web.com. There are only two notable differences to a non-tls ingress. The first one is the cert-manager.io/cluster-issuer
annotation, specifying that our previously production issuer letsencrypt-prod should be in charge of certificate handling. The second one is the tls field, specifying which domains should be included in the generated cert, and it's secretName defining the name of the secret that the generated certificate information should be stored in.
Once deployed, cert-manager will automatically fetch an SSL certificate for this ingress and also renew it in the background once expiration comes near. You can view the newly created certificate with kubectl
:
kubectl describe certificate sample-web-ingress-cert
This will return a lot of information about the certificate and it's current state. If your ingress is struggling to retrieve a certificate automatically, the Events
field of this output is a great first start to figure out where things went wrong.