Dominik Honnef

Managing Let's Encrypt certificates in Kubernetes with kube-cert-manager

Published:
Last modified:
by

Kubernetes provides a way of scheduling and managing resources such as containers, storage and load balancers in a highly automatic and easy fashion. It’s a prime example of Infrastructure as Code.

Let’s Encrypt, by its use of the ACME protocol, provides a simple and automatic way of obtaining TLS certificates that are trusted by all major browser vendors, completely for free.

In a lot of scenarios it can make sense to combine Kubernetes and Let’s Encrypt and to not have to deal with creating or renewing certificates by hand ever again. This is where kube-cert-manager comes into play: it offers an ACME client that is integrated with Kubernetes; requesting, renewing and deleting certificates as needed.

Features

kube-cert-manager provides numerous features that make managing Let’s Encrypt certificates a breeze.

The most obvious feature is, of course, requesting certificates. It can be instructed to do so in two different ways. The first, slightly more manual way, is by creating a Certificate resource. This resource will encapsulate all the necessary information, such as the domain name. kube-cert-manager, when seeing such a resource, will go and talk to Let’s Encrypt, request a certificate, and upon success create a new Kubernetes Secret to store the certificate in. At this point, you can use the secret in any way you usually would usually, most likely by mounting it in a container to use the certificates in a web server or similar.

The more automatic way hooks into Kubernetes Ingress objects. Ingress objects describe external load balancers and URL routing rules. Part of their job is terminating TLS connections. For this, the user can specify a list of hosts and Secret names that should contain the certificates. If you apply the right annotations to the Ingress resource, kube-cert-manager will pick them up and automatically populate the secrets with certificates.

Requesting certificates from Let’s Encrypt requires passing a challenge-response protocol to prove that one is in control of the domain. kube-cert-manager, via the use of lego, provides both HTTP and DNS based challenges. For the DNS challenge, it supports over a dozen of DNS providers, such as Google Cloud DNS or Digital Ocean.

Of course requesting certificates is only half the job: They also need to be renewed regularly: kube-cert-manager will do this automatically for you. If your load balancer or services support detecting file changes to reload certificates, you won’t need to do anything. For Go programs, there is kube-cert-http. For other software you will have to write your own adapters and reload logic, but that should be relatively simple.

kube-cert-manager will also delete old, unused certificates, but that goes without saying.

Installation

The project comes with detailed documentation on installation and deployment. I will refrain from copy & pasting it here.

Examples

The following examples are supposed to give you a feel for what it is like working with kube-cert-manager. Check the official documentation for a full reference of the resource formats.

Certificate objects

The first example demonstrates the use of Certificate objects. These are standalone resources that specify a certificate and cause kube-cert-manager to request a certificate and store it in a secret. The secret will exist for as long as the Certificate object exists.

apiVersion: "stable.k8s.psg.io/v1"
kind: "Certificate"
metadata:
  name: "psg-dot-io"
spec:
  domain: "psg.io"
  email: "admin@psg.io"
  provider: "googlecloud"

A secret that is created this way can be used like any other secret, for example by mounting it into a container, like in the following example:

spec:
  containers:
  - name: my-app
    image: ...
    args:
      - "-tls-cert=/etc/tls/psg.io/tls.crt"
      - "-tls-key=/etc/tls/psg.io/tls.key"
    volumeMounts:
      - name: psg-io
        mountPath: /etc/tls/psg.io
  volumes:
    - name: psg-io
      secret:
        secretName: psg.io

Ingress objects

The next example demonstrates the use of Ingress resources. kube-cert-manager will automatically extract the domain names and secret names from Ingress resources and populate the secrets with certificates.

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress
  annotations:
    stable.k8s.psg.io/kcm.enabled: "true"
    stable.k8s.psg.io/kcm.provider: "googlecloud"
    stable.k8s.psg.io/kcm.email: "admin@psg.io"
spec:
  tls:
  - hosts:
    - psg.io
    secretName: hello-secret
  rules:
  - host: "psg.io"
    http:
      paths:
      - path: /hello-world
        backend:
          serviceName: helloworld
          servicePort: 80

Given this example, the load balancer created by an Ingress controller will terminate TLS connections using a Let’s Encrypt certificate that is stored in the secret named hello-secret.

Summary

Kubernetes automates infrastructure, Let’s Encrypt automates certificates, and kube-cert-manager is the beautiful marriage of the two. It can be added to an existing Kubernetes setup without much effort and is definitely worth checking out.