13. February 2022 7 min read

Traefik v2 and LetsEncrypt WITHOUT cert-manager on RaspberryPi4 kubernetes cluster

I have already presented a solution with Traefik v2 and Cert manager as how to automatically renew your Letsencrypt certificates, but after recent update to 2.6 I figured out that there is a much easier version, which does not require cert-manager at all. My current setup is Kubernetes 1.22.4, on mixed Raspberry Pi 4 and Raspberry Pi 3 cluster, both with 32 bit arm operating systems (Raspbian).
I will skip basic installation as this point assumes you already have a cluster up and running, but you live without LoadBalancer since Traefik replaces load balancers like MetalLB, so you do not need one. We will use Helm 3 to install stuff on our cluster as that is easy and fast way, but we will have to modify some of the values to get it working nicer. Traefik has great installation guides and documentation, so I will skip the commands for setting up the repo like helm repo add ... and will drop directly to the changes in values and update/install commands.

Traefik v2 and https

Traefik Helm chart still does not support direct ACME Certificates for certificateresolvers but with some minor tweaks it can be done. The simple exercise here will be to expose the Traefik Dashboard to internet (just for test, do not keep it exposed, but use basicAuth module to protect it with username and password) via https. Let`s first check the values we need to change, and below I will write some notes that I have observed and the problems that I needed to overcome.

# traefik2-helm-values.yaml
# ...
# Create an IngressRoute for the dashboard
ingressRoute:
  dashboard:
    enabled: true
    # Additional ingressRoute annotations (e.g. for kubernetes.io/ingress.class)
    annotations: {}
    # Additional ingressRoute labels (e.g. for filtering IngressRoute by custom labels)
    labels: {}
# ...
additionalArguments:
  - "--certificatesresolvers.letsencrypt.acme.email=youremail"
  - "--certificatesresolvers.letsencrypt.acme.storage=/data/acme.json"
  - "--certificatesresolvers.letsencrypt.acme.caserver=https://acme-v02.api.letsencrypt.org/directory"
  - "--certificatesResolvers.letsencrypt.acme.tlsChallenge=true"
  - "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
# ...
# Configure ports
ports:
  # The name of this one can't be changed as it is used for the readiness and
  # liveness probes, but you can adjust its config to your liking
  traefik:
    port: 9000
    # ... Keep in mind we want to expose this ourselves not automatically and on master node 443 port
    expose: false
    # The exposed port for this service
    exposedPort: 9000
    # The port protocol (TCP/UDP)
    protocol: TCP
# ...
  websecure:
    port: 8443
    # hostPort: 8443
    expose: true
    exposedPort: 443
    # The port protocol (TCP/UDP)
    protocol: TCP
    # nodePort: 32443
    # Enable HTTP/3.
    # Requires enabling experimental http3 feature and tls.
    # Note that you cannot have a UDP entrypoint with the same port.
    # http3: true
    # Set TLS at the entrypoint
    # https://doc.traefik.io/traefik/routing/entrypoints/#tls
    tls:
      enabled: true
      # this is the name of a TLSOption definition
      options: ""
      certResolver: "letsencrypt"
# ...
service:
  enabled: true
  type: LoadBalancer
  # ...
  externalIPs:
    - your.master.node.host.ip.which.is.exposed.to.internet

Above commands set certResolver to letsencrypt for https (websecure) and add certificateresolver letsencrypt to Traefik binary via additional arguments. The Letsencrypt stuff is needed to be filled by your email address. After that we do not want to expose dashboard port 9000 to outside world, but we will rather write our own ingressroute to expose it on standard https port of 443. Next we enable LoadBalancer feature of Traefik and set the externalIP to your master`s node external IP, which is exposed to internet as either DMZ or normal port forwarding on your router. Keep in mind that this should not be mistaken as your public IP in most cases (unless your RPI directly connects to internet).

With this all set, you can run the helm command

helm upgrade traefik traefik/traefik --values traefik2-helm-values.yaml --namespace kube-system

Since dashboard already has IngressRoute based on above chart it is for /dashboard only, but we want to expose it to outside world as well. Just note, that this is the same way you can expose any other pod out there

# traefik-dashboard.yaml
kind: Service
apiVersion: v1
metadata:
  labels:
    k8s-app: traefik
  name: traefik-dashboard
  namespace: kube-system
spec:
  ports:
    - name: dashboard
      port: 9000
      targetPort: 9000
  selector:
    app.kubernetes.io/instance: traefik
    app.kubernetes.io/name: traefik
---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: traefik-dashboard-ingress
  namespace: kube-system
spec:
  entryPoints:
    - websecure
  routes:
    - match: Host(`example.com`)
      kind: Rule
      services:
        - name: traefik-dashboard
          kind: Service
          port: 9000
  tls:
    certResolver: letsencrypt

Above yaml defines a Service called traefik-dashboard, which links to pods port 9000 and then creates IngressRoute, which tells Traefik to direct all traffic coming to entryPoint websecure with host example.com to service traefik-dashboard and port 9000.

Now lets apply this to our cluster with kubectl

kubectl apply -f traefik-dashboard.yaml

After sometime your browser should be serving the Traefik Dasbhoard on HTTPS of your host. Some common things you could miss is like setup of your DNS server to point to your Kubernetes cluster public IP or forwarding some ports (we only need 80 and 443) on routers to your kubernetes master. Keep in mind that 9000 is clusters internal port in this case and that only http and https ports are exposed. If you get User forbidden error then you should create a clusterrolebinding

kubectl create clusterrolebinding --user system:serviceaccount:kube-system:default kube-system-cluster-admin --clusterrole cluster-admin

Newest from this category: