Automating ingress SSL Certificates on Kubernetes with Cert-Manager

Table of contents

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.

More articles

Using Private Registries with Kubernetes

Deploying private container images

Installing ingress-nginx on K3S

Setting up the default ingress controller

Dealing with pagination queries in SQL

The difficult choice behind chunking results into simple pages

Understanding postgres query plans

Making sense of postgres explanations

Fixing mixed content issues

Fixing holes in encrypted web traffic