Træfik in Kubernetes with manual certificate configuration

These examples assume that Træfik proxy is installed and is fully functional, probably using the install Traefik using the helm chart instructions. Do not just follow the quick start with Kubernetes instructions as that does not provide a fully functional Træfik install.

Manually add a certificate as a Secret

Using most TLS certificate authorities will result in having a private key file and a certificate file. When using the ACME protocol, for instance with LetsEncrypt, the process ends up with four files in a folder - the files privkey.pem and fullchain.pem are the two required files.

A Kubernetes tls Secret manifest file must be created and applied to the correct namespace in your cluster.

This command will create a Kubernetes tls Secret, but it will not replace a certificate when it already exists.

kubectl create secret tls ${NAME_OF_SECRET} \
    --namespace ${NAME_OF_NAMESPACE} \
    --key etc/live/lxiv.uk/privkey.pem \
    --cert etc/live/lxiv.uk/fullchain.pem

The kubectl apply command will replace a manifest which is already deployed, so a better form of kubectl command is to create the manifest locally, by using the --dry-run=client -o yaml command line switches, and pipe that manifest directly into a kubectl apply command.

For example - this will create a Secret named whoami-tls in the default namespace - assuming you correctly set the path to the privkey.pem and fullchain.pem files.

kubectl create secret tls whoami-tls \
    --namespace default \
    --key ${PATH_TO}/privkey.pem \
    --cert ${PATH_TO}/fullchain.pem \
    --dry-run=client -o yaml \
    | kubectl apply -f -

Deploy “who am I” app to use the certificate

The following manifest will demonstrate the use of the certificate with a simple who am I application provided by Træfik, although any other simple HTTP demonstration app can be used as an alternative.

A Deployment of the traefik/whoami image is created, a Service is created exposing the deployment internally within the Kubernetes cluster, and Træfik IngressRoute is created to inform Træfik of the hostname and path on which to expose the web-application, and which Secret to use containing the private key and certificate for the TLS encryption.

---
kind: Deployment
apiVersion: apps/v1
metadata:
  name: whoami
  labels:
    app: whoami

spec:
  replicas: 1
  selector:
    matchLabels:
      app: whoami
  template:
    metadata:
      labels:
        app: whoami
    spec:
      containers:
        - name: whoami
          image: traefik/whoami
          ports:
            - name: web
              containerPort: 80
          resources:
            limits:
              memory: "200Mi"
              cpu: 300m
            requests:
              memory: "100Mi"
              cpu: 1m
      enableServiceLinks: false

---
apiVersion: v1
kind: Service
metadata:
  name: whoami

spec:
  ports:
    - name: web
      port: 80
      targetPort: web

  selector:
    app: whoami

---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
  name: whoami
spec:
  entryPoints:
    - websecure
  routes:
    - kind: Rule
      match: Host(`whoami.example.com`)
      services:
        - kind: Service
          name: whoami
          namespace: default
          port: web
          passHostHeader: true
  tls:
    secretName: whoami-tls

This manifest is available to download here. It can be easily reused and adapted, for instance by applying a Kubernetes kubectl kustomization file, which might look like this:

namespace: default
resources:
  - whoami.yaml
patches:
  - target:
      group: traefik.io
      version: v1alpha1
      kind: IngressRoute
      name: whoami
    patch: |
      - op: replace
        path: /spec/routes/0/match
        value: Host(`your.host.name`) && PathPrefix(`/`)

Save that as kustomization.yaml into the same folder you saved whoami.yaml, replace your.host.name with the publicly available hostname in your TLS certificate, and apply the kustomization with this command:

kubectl kustomize . | kubectl apply -f -

The whoami application should be visible at https://your.host.name - assuming any DNS configuration, and network configuration to route or NAT to your Træfik Service has been applied.

Ingress vs IngressRoute

In my opinion, a worse alternative to using a Træfik specific IngressRoute is using the Kubernetes built-in Ingress.

The biggest problem with a Kubernetes Ingress is that the Ingress will apply routes to Træfik’s service on both web (TCP port 80 - http) and websecure (TCP port 443 - https) EntryPoints. Which is unlike Træfik’s IngressRoute, which binds to specific EntryPoints.

An example using an Ingress which mimics the IngressRoute configuration might look something like this:

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: whoami

spec:
  tls:
    - hosts:
      - whoami.example.com
      secretName: whoami-tls
  rules:
  - host: whoami.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: whoami
            port:
              name: web

Note that Kubernetes have stopped developing any changes to Ingress and are developing a new Gateway API which Træfik will also support.

Deploy Google’s “hello world” app to use the certificate

As above, the following manifest will demonstrate the use of the certificate with a simple hello world web application provided by Google.

A Deployment of the gcr.io/google-samples/hello-app image is created, a Service is created exposing the deployment internally within the Kubernetes cluster, and two Træfik IngressRoutes are created to inform Træfik of the hostname and path on which to expose the web-application - one for http and one for https. The Secret is used the https IngressRoute for the TLS encryption, and a Træfik Middleware is used to redirect all http connections to https.

Warning

The Google hello-app does not work on arm/v7 or arm64 - it will not work on a Raspberry Pi.

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-app
  labels:
    app: hello-app

spec:
  replicas: 1
  selector:
    matchLabels:
      app: hello-app
  template:
    metadata:
      labels:
        app: hello-app
    spec:
      containers:
        - name: hello-app
          image: "gcr.io/google-samples/hello-app:1.0"
          ports:
            - name: web
              containerPort: 8080
              protocol: TCP
          resources:
            requests:
              cpu: 50m
              memory: 64Mi
            limits:
              cpu: 1000m
              memory: 128Mi
      enableServiceLinks: false

---
apiVersion: v1
kind: Service
metadata:
  name: hello-app

spec:
  selector:
    app: hello-app
  ports:
    - name: web
      port: 80
      targetPort: web

---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
  name: hello-app-web
spec:
  entryPoints:
    - web
  routes:
    - kind: Rule
      match: Host(`hello.example.com`) && PathPrefix(`/`)
      middlewares:
        - name: "hello-app-redirect"
      services:
        # the service will be never called because of the redirect middleware
        - kind: Service
          name: hello-app
          namespace: default
          port: web
          passHostHeader: true

---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
  name: hello-app-websecure
spec:
  entryPoints:
    - websecure
  routes:
    - kind: Rule
      match: Host(`hello.example.com`) && PathPrefix(`/`)
      middlewares:
        - name: "hello-app-redirect"
      services:
        - kind: Service
          name: hello-app
          namespace: default
          port: web
          passHostHeader: true
  tls:
    secretName: hello-app-tls

---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: hello-app-redirect

spec:
  redirectScheme:
    scheme: https
    permanent: true

This manifest is available to download here. As above, it can be easily reused and adapted by applying a Kubernetes kubectl kustomization like this.

namespace: default
resources:
  - hello-app.yaml
patches:
  - target:
      group: traefik.io
      version: v1alpha1
      kind: IngressRoute
      name: hello-app-web
    patch: |
      - op: replace
        path: /spec/routes/0/match
        value: Host(`your.host.name`) && PathPrefix(`/`)
      - op: replace
        path: /spec/routes/0/services/0/namespace
        value: default
  - target:
      group: traefik.io
      version: v1alpha1
      kind: IngressRoute
      name: hello-app-websecure
    patch: |
      - op: replace
        path: /spec/routes/0/match
        value: Host(`your.host.name`) && PathPrefix(`/`)
      - op: replace
        path: /spec/routes/0/services/0/namespace
        value: default

The hello-app application should be visible at to http://<your.host.name> or https://<your.host.name>. If you went to http then your browser will be redirected to https and you’ll securely see the hello app.