Configure Cert Manager and Let's Encrypt in a Kubernetes Cluster with Traefik and Cloudflare

Introduction

If your DNS is managed by Cloudflare and you want to use DNS01 challenge with Cloudflare and Cert Manager in a Kubernetes Cluster, you can follow this guide.

Configuring Cloudflare:

Assuming you have created a Cloudflare account and added your domain, go to your Cloudflare Dashboard and point your domain to your Load Balancer IP. If you have used the Kubernetes on Hetzner guide, point your Hetzner Load Balancer IP address that you have just created. Under DNS add two A Record. One is for the root and one is for subdomains:

    Type       Name              Content           Proxy status       TTL       

      A              @              Your-LB-IP             DNS Only           Auto
      A              *              Your-LB-IP             DNS Only           Auto

Do not forget to disable proxy:

Screenshot 2022-11-01 at 16.53.45.png

Deploying Cert Manager:

First add the helm repo:

helm repo add jetstack https://charts.jetstack.io
helm repo update

create a values.yaml and add Cloudflare's dns as well:

installCRDs: true 
podDnsConfig:
  nameservers:
    - "1.1.1.1"
    - "9.9.9.9"

then install Cert manager:

helm install cert-manager jetstack/cert-manager -f values.yaml --namespace cert-manager --create-namespace --set installCRDs=true

Generate an Cloudflare API token like this:

Screenshot 2022-11-01 at 16.59.01.png

Add your Cloudflare Api Token as a secret in Kubernetes. If you are using GitOps, consider encrypting your secrets or use some kind of secret managing solution:

apiVersion: v1
kind: Secret
metadata:
  name: cloudflare-secret
  namespace: cert-manager
type: Opaque
stringData:
  cloudflare-token: yourtoken

Create your cluster issuers. One for staging and one for production.

Staging:

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-staging
spec:
  acme:
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    email: your@email.com
    privateKeySecretRef:
      name: letsencrypt-staging
    solvers:
      - dns01:
          cloudflare:
            email: your-cloudflare@email.com
            apiTokenSecretRef:
              name: cloudflare-secret
              key: cloudflare-token
        selector:
          dnsZones:
            - "your-domain.com"

Production:

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-production
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: your@email.com
    privateKeySecretRef:
      name: letsencrypt-production
    solvers:
      - dns01:
          cloudflare:
            email: your-cloudflare@email.com
            apiTokenSecretRef:
              name: cloudflare-secret
              key: cloudflare-token
        selector:
          dnsZones:
            - "your-domain.com"

You can now test it with an application. Below you will find an example app exposed with Traefik:

kubectl create deployment nginx --image=nginx 

kubectl expose deploy nginx --type=ClusterIP --port=80

create a Certificate for your application:

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: nginx.yourdomain.com
  namespace: default
spec:
  dnsNames:
    - nginx.yourdomain.com
  secretName: nginx-tls
  issuerRef:
    name: letsencrypt-staging
    kind: ClusterIssuer

then create an Ingressroute:

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: nginx
  namespace: default
  annotations:
    kubernetes.io/ingress.class: traefik-external
spec:
  entryPoints:
    - websecure
    - web
  routes:
    - match: Host(`nginx.yourdomain.com`)
      kind: Rule
      services:
        - name: nginx
          port: 80
    - match: Host(`www.nginx.yourdomain.com`)
      kind: Rule
      services:
        - name: nginx
          port: 80
  tls:
    secretName: nginx-tls

You can now access your application:

Screenshot 2022-11-01 at 17.20.07.png

You will see a warning about an unsecure connection. This is normal with staging. When you switch to the production, the error will disappear:

Screenshot 2022-11-01 at 18.30.41.png

Did you find this article valuable?

Support Alper Cicek by becoming a sponsor. Any amount is appreciated!