Enabling Cloudflare in front of your Kubernetes cluster with Traefik

- kubernetes traefik cloudflare

I’m still using my arm64 4 nodes cluster for experimentation and even to serve some websites. Since I wanted to test some new Cloudflare features, I migrated one of my domain which has a bunch of websites on it.

But first a quick and simple way to serve some static pages:

Serving Static Pages

One way is to build an image with the actual pages in it and let Kubernetes serves them.

Separate your websites into directories:

ls www
mysite.com subsite.mysite.com mysuperothersite.com

Using Caddy as base image, create a Dockerfile:

FROM caddy:2

COPY Caddyfile /etc/caddy/Caddyfile
ADD www/ /srv/

Create the proper Caddyfile:

{
	email youremail@yourdomain.com
	auto_https off
}

mysite.com:80 {
	root * /srv/mysite.com
	file_server
}
subsite.mysite.com:80 {
	root * /srv/subsite.mysite.com
	file_server
}
...

Caddy 2 enabled https by default, in our case we don’t want https to be enabled in those pods since the ingress will deal with it. Create your deployment and service, and let the ingress knows about it, in my case Traefik:

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: websites-ingress
  namespace: web
spec:
  entryPoints:
    - websecure
  routes:
    - match: Host(`mysite.com`) || Host(`subsite.mysite.com`) || Host(`mysuperothersite.com`) 

      middlewares:
        - name: compress
      kind: Rule
      services:
        - name: websites
          port: 80

Cloudflare and Traffic Encryption

Remember Cloudflare will proxy all the requests back to your cluster, it means you don’t need to have publicly valid certificates anymore (like Let’s encrypt), but Cloudflare will provide you with a certificate to sign the exchange between them and your ingress.

Go to your Cloudflare admin interface in SSL/TLS, then Origin Server, create a certifcate.
Store the public key in origin.pub the private part in origin.key.

As mentioned in Traefik documentation with Kubernetes the certificates can and must be provided by secrets.

Let’s create a secret in the correct Traefik namespace

kubectl -n kube-system create secret generic default-certificate --from-file=tls.crt=./origin.crt --from-file=tls.key=./origin.key

And point Traefik default store to the secret:

apiVersion: traefik.containo.us/v1alpha1
kind: TLSStore
metadata:
  name: default
  namespace: kube-system

spec:
  defaultCertificate:
    secretName: default-certificate

You can now enable Cloudflare full (strict) mode:
Encrypts end-to-end, but requires a trusted CA or Cloudflare Origin CA certificate on the server.

Common pitfalls

Beware of the difference between store and certResolver:
On your IngressRoute you probably had a certResolver to handle let’s encrypt.

  tls:
    certResolver: default

On the domain handled by Cloudflare you need the default store (which is now the default).

  tls:
    store:
      name: default