High Availability Traefik for K8s (IngressRoute + Cert Manager + LetsEncrypt)

HA Traefik + CertManager + LetsEncrypt

Here I share the recipe for how to setup High Availability Traefik Proxy (multiple instances) for Kubernetes with TLS certificates obtained from LetsEncrypt with help of Cert Manager.

To get high availability setup for Traefik we will host multiple instances of Traefik on different hosts (or even in different availability zones). All of the Traefik instances need to load the same TLS certificates and equally participate in ACME http challenge process during obtaining the certificates from LetsEncrypt. Both can be achieved by using Cert Manager, which stores the TLS certificates in Kubernetes secrets (no need for PVC) and carries out LetEncrypt ACME http challenge through Kubernetes Ingress entities. We leave deployment of Cert Manager out of scope for this post. The following assumes that you have Cert Manager deployed.

Configuring Cert Manager for LetsEncrypt

In order to get certificates from LetsEncrypt we can define the following Issuers (CRD used by Cert Manager):

YAML
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-staging
spec:
  acme:
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    email: hostmaster@your-domain.tld # Replace this with your mail address
    privateKeySecretRef:
      name: letsencrypt-staging
    solvers:
    - http01:
        ingress:
          class: traefik
---
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: hostmaster@your-domain.tld # Replace this with your mail address
    privateKeySecretRef:
      name: letsencrypt-prod
    solvers:
    - http01:
        ingress:
          class: traefik

Configuring Traefik for Cert Manager

Note that we specified the “traefik” ingress class among ACME solvers. That is how Cert Manager will get the TLS certificates for our domains. Cert Manager can’t use IngressRoute CRD defined for Traefik as they are too application specific. Instead, it can use standard Ingress or newly emerged Gateway API Kubernetes entities. Here we use Ingress. That means that we need to enable Traefik to serve Kubernetes Ingress entities. That can be done, for instance, through CLI args:

YAML
...
      spec:
        containers:
        - name: traefik
          image: traefik:v2.9
          args:
            - --entrypoints.web.Address=:80
            - --entrypoints.websecure.Address=:443
            - --providers.kubernetescrd # needed for IngressRoutes
            - --providers.kubernetesingress # needed for cert-manger
          ports:
            - name: web
              containerPort: 80
            - name: websecure
              containerPort: 443

If you use IngressRoutes then you will have to enable both kubernetescrd and kubernetesingress Traefik configuration providers.

Defining “certificate” for IngressRoute

Now the Cert Manager will be able to finish the ACME http challenge for our domains. At this point we can define a certificate to obtain from LetsEncrypt. The following example defines the certificate that is used at this blog (note that you can define multiple DNS names for single certificate).

YAML
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: grechka.family-tls-cert
spec:
  secretName: grechka.family-tls-secret
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
  dnsNames:
    - grechka.family
    - www.grechka.family

Right after we create this entity in Kubernetes, Cert Manager will acquire the certificate. Now we can use the certificate in Traefik IngressRoute, like in the following example:

YAML
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: tls-dmitry-web-blog
spec:
...
  tls:
    secretName: grechka.family-tls-secret

That’s it! We have high availability Traefik with LetsEncrypt certificates.

Leave a Reply

Your email address will not be published. Required fields are marked *

%d bloggers like this: