Generate SSL Certificates with Traefik and Let's Encrypt

Traefik is awesome. It can use both file-based certificates and Kubernetes TLS Secret objects as SSL store.

Even it is possible to use SSL certificates generated by Let's Encrypt (privkey.pem and fullchain.pem from /etc/letsencrypt/live direcotory) by creating a TLS secret from these files.

But what if you want to generate certificates using Traefik itself? Luckily Traefik has full support for all Let's Encrypt challenges (http, https and dns based verification). Let's jump in.

First, ensure that Traefik has connectivity to the internet. Without internet connectivity, Traefik will not be able to send certificate renewal requests to ACME servers.

Second, if you have multiple replicas of Traefik running in the cluster (DaemonSet or Deployment) then you can reduce the replicas to 1. This will lower the chance of failed verification attempts and being restricted to issue certificates for a week.

Third, Traefik stores the keys and certificates in a JSON file named acme.json. This must persist when Traefik restarts. Otherwise, Traefik will try to re-issue the certificate and your domain could be blacklisted for a while.

To enable ACME based resolver, add the following parameters email, storage and challenge as Traefik command line parameters. You are free to choose any name. I used letsencrypt in this case.

...
- args:
  - --log.level=DEBUG
  - --entrypoints.web.address=:80
  - --entrypoints.websecure.address=:443
  - --certificatesresolvers.letsencrypt.acme.email=me@example.com
  - --certificatesresolvers.letsencrypt.acme.storage=/etc/traefik/acme/acme.json
  - --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web
  - --serversTransport.insecureSkipVerify=true
  image: traefik:v2.9
  name: traefik
...

Then let's mount the path /etc/traefik/acme as a persistence volume. You can use hostPath, nfs, glusterfs or anything compatible with Kubernetes. But make sure that the mount path is shared across all Traefik pods running in the cluster.

  volumeMounts:
  - name: acme
    mountPath: /etc/traefik/acme
volumes:
- name: acme
  nfs:
    path: /data/traefik-system/acme
    server: 192.168.100.200

Once Traefik pods are in Running state, let's create an IngressRoute object that uses letsencrypt resolver as SSL store. Here is one example.

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: my-app
spec:
  entryPoints:
  - websecure
  routes:
  - kind: Rule
    match: Host(`my-app.com`)
    services:
    - name: my-app
      port: 80
  tls:
    certResolver: letsencrypt

Once this resource is applied, Traefik will try to issue a certificate using ACME API and disable all other ingress hosts for a few seconds. Upon a successful issue, the acme.json file will be generated.

Please note that wildcard certificates can only be generated using DNS-based verifications. So you have to use the sans sections in the tls block of IngressRoute carefully.

I hope the post helps you all.