Before publishing any service over the internet, it is crucial to configure https. We are doing it mainly for security, privacy and data integrity. Browsers will be annoying users, if your page uses self signed certificates, or do not have it at all.

In terms of obtaining certificates we have two options. We can buy one year certificate from CA, and we need to remember to change it before it expires. Or we can have it for free, and have it refreshed automatically. In this post, I will cover latter option.

First, we need to install cert-manager. It is a handy tool for obtaining, renewing and using tls certificates. Below command will deploy it to our cluster

kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.16.1/cert-manager.yaml

Then we need to configure cert-issuer

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    email: ${EMAIL}
    server: https://acme-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      name: letsencrypt-prod
    solvers:
    - http01:
        ingress:
          class: traefik

save it, change the e-mail, and apply the file

Now, lets create traefik middleware. It will redirect our traffic from http (if any) to https:

apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
  name: redirect-https
spec:
  redirectScheme:
    scheme: https
    permanent: true

It is not a surprise, but before obtaining the certificate, we need a domain. Configure record A, and point it to your cluster first. I am using Cloudflare, since it has terraform provider, but I will cover it later.

If you already configured DNS record, you can check the propagation with dnschecker.org , because this operation can take some time.

Now, we need some service we want to publish. Lets say we want a wordpress blog.

helm install wordpress oci://registry-1.docker.io/bitnamicharts/wordpress

After a few moments, we have wordpress and database installed.

kubectl get pvc \                                                                                                                          
-o custom-columns="NAME:.metadata.name,STORAGECLASS:.spec.storageClassName"
NAME                       STORAGECLASS
data-wordpress-mariadb-0   longhorn
wordpress                  longhorn

notice, it is using longhorn already.

Last, but not least, lets configure the ingress resource. Here is the part, where all the magic happens.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: blog-tls-ingress
  annotations:
    spec.ingressClassName: traefik
    cert-manager.io/cluster-issuer: letsencrypt-prod
    traefik.ingress.kubernetes.io/router.middlewares: cert-manager-redirect-https@kubernetescrd
spec:
  rules:
    - host: blog.piasecki.it
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: wordpress
                port:
                  number: 80
  tls:
    - secretName: blog-tls
      hosts:
        - blog.piasecki.it

I will not go into boring details. Anyway, here is the high-level flow:

  • traefik creates cert request
  • cert-manager passes challenge, to prove ownership of the domain
  • traefik publishes it, so LetsEncrypt can read the challenge
  • cert-manager stores the certificate as k8s secret
  • traefik uses the certificate to decrypt the traffic, and route it to the service (wordpress)

LetsEncrypt certificates are valid for 90 days. But it is not a drawback. It is additional motivation to automate it using cert-manager or Certbot. Those tools are renewing your certificates every 30 days.

Leave a Reply

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

+ ,