In this blog post, we are pleased to introduce Kube-Lego, an open source tool for automated Let’s Encrypt TLS-enabled web services running in Kubernetes.
TLS has become increasingly important for production deployment of web services. This has been driven by revelations of surveillance post-Snowden, as well as the fact that Google now favours secure HTTPS sites in search result rankings.
An important step towards increased adoption of TLS has been the availability of
Let’s Encrypt. It provides an easy, free-of-charge way to obtain certificates. Certificates are limited to a 90-day lifetime and so the free certificate authority (CA) encourages full automation for ease-of-use. At the time of writing, Let’s Encrypt has approaching 3.5 million unexpired certificates so adoption has certainly been strong.
Kube-Lego automates the process in Kubernetes by watching ingress resources and automatically requesting missing or expired TLS certificates from Let’s Encrypt.
In order to automate the process of verification and certificate issuance for
Let’s Encrypt’s CA, the ACME (Automated Certificate Management Environment)
protocol is used. It specifies an API that can be integrated into many products
that require publicly trusted certificates.
To interact with the CA’s ACME server, clients are required to
authenticate with a private/public key pair (account). This helps to identify
the user later for actions like extension or revocation of certificates. Let’s
Encrypt supports only domain validation and requires you to specify every
valid domain individually, so while a certificate can be valid for multiple
hostnames using SAN, there is currently no support for wildcard certificates.
Validation methods
Let’s Encrypt allows you to prove the validity of a certificate request
with four methods. They all use a so-called ‘key auth challenge response’, which
is derived from the account’s key pair.
- Simple HTTP: The CA connects to the specified URL
(http://$/.well-known/acme-challenge/$) to verify the
authenticity of a certificate request. The response of the HTTP server has to
contain the key auth. - TLS-SNI: With this method, the CA connects to the requested domain
name via HTTPS and selects the verification hostname
$.$.acme.invalid via SNI. The returned certificate
is not verified, it only has to contain the verification hostname. - DNS: A TXT-record _acme-challenge.$ has to be published,
to verify the authenticity of your request via the DNS method. The content of
this records has to include the key auth. - Proof of Possession of a Prior Key: If you already have a valid
certificate for the domain name you want to request another certificate. You can then use this method to get validated.
Kube-Lego brings fully automated TLS management to a Kubernetes cluster.
To achieve this it interfaces with the Kubernetes API on one side and an ACME
enabled CA on the other. Kube-Lego is written in Go and uses xenolf’s
ACME client implementation Lego for communicating with Let’s
Encrypt (this explains the project name). Currently, the only
implemented validation method is Simple HTTP
Pre-requisites
To use Kube-Lego you need a working Kubernetes cluster. The minimum
version supported is 1.2, as this includes TLS support for ingress resources. There are plenty of ways getting Kubernetes
bootstrapped; for instance, take a look at this Getting Started
Guide from the Kubernetes
project.
Note: Jetstack will also soon open source its cluster provisioner tool.
Another requirement for using Kube-Lego is a supported
ingress controller. The only supported controller at the moment is the
nginx-ingress-controller from Kubernetes’ contrib project. The current
release of the upstream controller needs a simple modification to fully support
Kube-Lego. There is already a pull
request filed to integrate
this change into the next upstream release. Meanwhile you can use a modified
build of the
nginx-ingress-controller.
Before you can use Kube-Lego you have to make the nginx-ingress-controller pods
accessible publicly. This usually happens with a service resource of the type
LoadBalancer.
Depending on the environment the cluster is running, this will create an
ELB/Forwarding Rule and you can point the domains you wish to use to that entry
point into your cluster.
Validity check
After starting up, Kube-Lego looks at all ingress objects in all namespaces in the Kubernetes cluster. If the ingress is annotated with kubernetes.io/tls-acme: “true”, Kube-Lego will check the TLS configuration and make sure that the specified secret:
- Exists and contains a valid private/public key pair;
- The certificate is not expired;
- The certificate covers all domain names specified in the ingress config.
Let’s take a look at the following example of an ingress resource:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: hello-world
annotations:
# enable kube-lego for this ingress
kubernetes.io/tls-acme: “true”
spec:
# this enables tls for the specified domain names
tls:
– hosts:
– demo.kube-lego.jetstack.net
secretName: hello-world-tls
rules:
– host: demo.kube-lego.jetstack.net
http:
paths:
– path: /
backend:
serviceName: hello-world
servicePort: 80
Certificate Request
Let’s assume we haven’t run Kube-Lego before, so neither the certificate nor
the user account exists. The Kube-Lego validity check comes to the conclusion
that it needs to request a certificate for the domain
demo.kube-lego.jetstack.net.
Before requesting the certificate, Kube-Lego sets up the challenge endpoint
(/.well-known/acme-challenge/) in a separate ingress resource named
kube-lego. This resource is meant to only be used by Kube-Lego and the endpoint
will be reachable over the public URL. This
makes sure that actual traffic can reach the cluster and we do not
unnecessarily try to validate with Let’s Encrypt.
Kube-Lego looks for the secret kube-lego-account; if it does not
exist, Kube-Lego creates it by registering with Let’s Encrypt. Finally, the
request for the certificate can be made with Let’s Encrypt. Kube-Lego
responds to the HTTP validation via the challenge endpoint and then finally
receives the certificate, which is stored into the secret hello-world-tls.
The following diagram illustrates this flow and the various interfaces.
Kube-Lego process
Demo
If you want to run these examples, you can always find the latest
version on GitHub.
A short demo was also part of the Kubernetes Community Hangout on June 2nd. See the recording here.
A screencast of an extended demo can be found here:
Screencast
Future work
This is a very early project and does not cover all common use cases.
Feel free to report any issues and enhancements via GitHub
Issues. You can also see some
already identified issues there.