Manage TLS termination in your Kubernetes cluster with Cert-Manager and Let’s Encrypt

,

In previous articles we talked about installing a k3s clusterusing Longhorn for resilient storage and using MetalLB for load-balancing. We still need to address a couple of things before deploying a simple workload.

If you plan to expose some Kubernetes workloads as a public domain or subdomain, you’ll most likely want either a mix of http and https traffic or exclusively https. In order to achieve https, your domain/subdomain will have to present a valid certificate, which a browser can then validate.

If you feel the need to find out more on the topic, you can check this video about TLS and this article about SSL/TLS termination.

I did previously touch on this topic in an article about using Nginx Proxy Manager for your Docker workloads. This is similar, but in the context of Kubernetes.

This article assumes you have a DNS provider with API access, in my case it’s Cloudflare.

Setup

First, install Cert-Manager in your cluster by running this command:

$ kubectl apply -f https://github.com/cert-manager/cert-manager/releases/latest/download/cert-manager.yaml

This will also create the cert-manager namespace, so you don’t have to do that.

Next, we’ll create a K8s secret containing the DNS provider API token. If you need some help generating a token for Cloudflare, you can check this article. The main thing is it needs to have permissions to edit the DNS of the domains (zones) you will want managed by Cert-Manager (see screenshot below).

Create a file named cloudflare-api-token-secret.yml with the following content:

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

Replace YOUR_CLOUDFLARE_API_TOKEN with the token you previously generated.

You can create it by running:

$ kubectl apply -f cloudflare-api-token-secret.yml

Next, we’ll create a ClusterIssuer custom resource, used by Cert-Manager. Create a file named cluster-issuer.yml with this content:

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-dns
spec:
  acme:
    email: [email protected]
    server: https://acme-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      name: letsencrypt-dns-account-key
    solvers:
    - dns01:
        cloudflare:
          apiTokenSecretRef:
            name: cloudflare-api-token-secret
            key: api-token

Replace [email protected] with your actual email address. You can see it references the secret you previously created for Cloudflare. Apply it by running:

$ kubectl apply -f cluster-issuer.yml

That should be it, you should now be able to use it on your ingress resources. For example, in a previous article we installed Longhorn for resilient storage. In order to expose Longhorn’s UI through an ingress, you’d define the ingress like this:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: longhorn-ingress
  namespace: longhorn-system
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-dns
    traefik.ingress.kubernetes.io/router.entrypoints: websecure
spec:
  rules:
  - host: longhorn.k3s.alexmihai.rocks
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: longhorn-frontend
            port:
              number: 80
  tls:
  - hosts:
    - longhorn.k3s.alexmihai.rocks
    secretName: longhorn-k3s-tls

You can see it references the ClusterIssuer we have defined and in the tls section of the definition, it asks for a certificate for the longhorn.k3s.alexmihai.rocks host, which will be stored in the longhorn-k3s-tls secret.

Hope this helps, have fun clickity-clacking.

Comments

Leave a Reply

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