Hello, and welcome!
If you're looking for the most efficient process of configuring HTTPS for your applications, you're in the right place.
In this article, I'll show you how to configure HTTPS on your Kubernetes apps using Traefik Proxy. Among other things, Traefik Proxy provides TLS termination, so your applications remain free from the challenges of handling SSL.
Before I jump in, let’s have a look at a few prerequisites. If you want to follow along with this tutorial, you need to have a few things set up first:
- A working Kubernetes cluster. The Traefik Labs team likes to use k3d for development and demonstrations. K3d creates a local Kubernetes cluster within Docker. It uses the K3s Kubernetes distribution, currently packaged with Traefik Proxy version 2.4.8. You also need to enable port forwarding for port 443. This is the port that allows us to handle HTTPS requests when using Traefik Proxy. Once you have k3d installed, you can spin up a cluster with this command:
$ k3d cluster create dash -p "443:443@loadbalancer"
- A public IP to host the cluster. The IP allows us to configure and verify various TLS specific features. When you see 18.104.22.168 used in this article, replace it with the public address for your own cluster. To avoid having to configure DNS, we'll use subdomains provided by the free and wonderful services of nip.io.
kubectlcommand-line tool. Make sure you configure it to point to your cluster. If you created your cluster using K3d and the instructions above, this will already be done for you.
- A Kubernetes Namespace named
dev.This is used for deploying your applications.
$ kubectl create namespace dev
HTTPS termination is the simplest way to enable HTTPS support for your applications. The termination process makes sure that all TLS exchange happens between the Traefik Proxy server and the end-user. When you do this, your applications remain focused on the actual solution they offer instead of also having to manage TLS certificates. In the following sections, we'll cover the scenarios of default certificates, manual certificates, and automatic certificates from Let's Encrypt.
Traefik Proxy handles requests using
webscure entrypoints. HTTPS is enabled by using the
webscure entrypoint. Create a
whoami Kubernetes IngressRoute which will listen to all incoming requests for whoami.22.214.171.124.nip.io on the
websecure entrypoint. Traefik performs HTTPS exchange and then delegates the request to the deployed
whoami Kubernetes Service.
apiVersion: traefik.containo.us/v1alpha1 kind: IngressRoute metadata: name: whoami namespace: dev spec: entryPoints: - websecure routes: - kind: Rule match: Host(`whoami.126.96.36.199.nip.io`) services: - name: whoami port: 80
whoami application, service, and the
IngressRoute. You can find the
whoami.yaml file here.
$ kubectl apply -f whoami.yaml deployment.apps/whoami configured service/whoami configured ingressroute.traefik.containo.us/whoami configured
Open the application in your browser using a URL like https://whoami.188.8.131.52.nip.io (modifying the IP to reflect your public IP). The browser displays warnings due to a self-signed certificate. Accept the warning and look up the certificate details.
Alternatively, you can also use the following
$ curl -k -vI https://whoami.184.108.40.206.nip.io/ ### Abridged for Brevity ### * Server certificate: * subject: CN=TRAEFIK DEFAULT CERT * start date: Nov 11 06:31:43 2021 GMT * expire date: Nov 11 06:31:43 2022 GMT * issuer: CN=TRAEFIK DEFAULT CERT * SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
As shown above, the application relies on Traefik Proxy-generated self-signed certificates — the output specifies
CN=TRAEFIK DEFAULT CERT. The certificate is used for all TLS interactions where there is no matching certificate.
When you have certificates that come from a provider other than Let's Encrypt (either self-signed, from an internal CA, or from another commercial CA), you can apply these certificates manually and instruct Traefik to use them. Each will have a private key and a certificate issued by the CA for that key. To demonstrate this scenario in Traefik, let's generate a self-signed certificate and apply it to the cluster.
OpenSSL is installed on Linux and Mac systems and is available for Windows. It provides the
openssl command, which you can use to create a self-signed certificate. Use the configuration file shown below to quickly generate the certificate (but be sure to change the
DNS.1 lines to reflect your public IP).
[ req ] default_bits = 2048 distinguished_name = req_distinguished_name req_extensions = req_ext prompt = no [ req_distinguished_name ] C = US ST = VA CN = whoami.220.127.116.11.nip.io [ req_ext ] subjectAltName = @alt_names [ alt_names ] DNS.1 = whoami.18.104.22.168.nip.io DNS.2 = whoami.127.0.0.1.nip.io
Traefik Proxy would match the requested
hostname (SNI) with the certificate
FQDN before using the respective certificate. You can generate the self-signed certificate pair in a non-interactive manner using the following command:
$ openssl req -nodes -new -x509 -keyout server.key -out server.crt -config openssl.conf -days 365 Generating a 2048 bit RSA private key ................................................................................................................................................................................+++ ..+++ writing new private key to 'server.key' -----
Before we can update the IngressRoute to use the certificates, the certificate and key pair must be uploaded as a Kubernetes Secret with the following two attributes:
tls.crt: The certificate.
tls.key: The non-encrypted private key. Traefik Proxy does not work with encrypted keys.
Create the Secret, using the following command:
$ kubectl create secret generic whoami-secret --from-file=tls.crt=./server.crt --from-file=tls.key=./server.key --namespace dev secret/whoami-secret created
IngressRoute and reference the Secret in the
apiVersion: traefik.containo.us/v1alpha1 kind: IngressRoute metadata: name: whoami namespace: dev spec: entryPoints: - websecure routes: - kind: Rule match: Host(`whoami.local`) services: - name: whoami port: 80 tls: secretName: whoami-secret
Deploy the updated
IngressRoute configuration and then open the application in the browser using the URL https://whoami.22.214.171.124.nip.io. The browser will still display a warning because we're using a self-signed certificate. Accept the warning and look up the certificate details.
If Traefik Proxy is handling all requests for a domain, you may want to substitute the default Traefik Proxy certificate with another certificate, such as a wildcard certificate for the entire domain. We do by creating a
TLSStore configuration and setting the
defaultCertificate key to the secret that contains the certificate.
apiVersion: traefik.containo.us/v1alpha1 kind: TLSStore metadata: name: default namespace: default spec: defaultCertificate: secretName: whoami-secret
Save that as
default-tls-store.yml and deploy it.
$ kubectl apply -f default-tls-store.yml
Let's Encrypt certificates
In the section above we deployed TLS certificates manually. When working with manual certificates, you, as the operator, are also responsible for renewing and updating them when they expire. Alternatively, you can also configure Traefik Proxy to use Let's Encrypt for the automated generation and renewal of certificates.
We do that by providing additional
certificatesresolvers parameters in Traefik Proxy static configuration. The
certificatesresolvers specify details about the Let's Encrypt account, Let's Encrypt challenge, Let's Encrypt servers, and the certificate storage.
apiVersion: helm.cattle.io/v1 kind: HelmChartConfig metadata: name: traefik namespace: kube-system spec: valuesContent: |- additionalArguments: - "--log.level=DEBUG" - "[email protected]" - "--certificatesresolvers.le.acme.storage=/data/acme.json" - "--certificatesresolvers.le.acme.tlschallenge=true" - "--certificatesresolvers.le.acme.caServer=https://acme-staging-v02.api.letsencrypt.org/directory"
To avoid hitting rate limits or being banned from Let's Encrypt, we recommend that you use the
acme-staging server for all non-production environments.
Save the configuration above as
traefik-update.yaml and apply it to the cluster.
$ kubectl apply -f traefik-update.yaml
Although you can configure Traefik Proxy to use multiple
IngressRoute is only ever associated with a single one. That association happens with the
tls.certResolver key, as seen below:
apiVersion: traefik.containo.us/v1alpha1 kind: IngressRoute metadata: name: whoami namespace: dev spec: entryPoints: - websecure routes: - kind: Rule match: Host(`whoami.126.96.36.199.nip.io`) services: - name: whoami port: 80 tls: certResolver: le
Make that change, and then deploy the updated
IngressRoute configuration. Reload the application in the browser, and view the certificate details.
Traefik Proxy provides several options to control and configure the different aspects of the TLS handshake. Several parameters control aspects such as the supported TLS versions, exchange ciphers, curves, etc. Take look at the TLS options documentation for all the details.
Before you enable these options, perform an analysis of the TLS handshake using SSLLabs. The SSLLabs service provides a detailed report of various aspects of TLS, along with a color-coded report.
The above report shows that the
whoami service supports TLS 1.0 and 1.1 protocols without forward secrecy key exchange algorithms.
An IngressRoute is associated with the application TLS options by using the
tls.options.name configuration parameter. The below configuration defines a
TLSOption resource with specific TLS and applies it to the
apiVersion: traefik.containo.us/v1alpha1 kind: TLSOption metadata: name: tlsoptions namespace: dev spec: minVersion: VersionTLS12 cipherSuites: - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 - TLS_AES_256_GCM_SHA384 - TLS_AES_128_GCM_SHA256 - TLS_CHACHA20_POLY1305_SHA256 - TLS_FALLBACK_SCSV curvePreferences: - CurveP521 - CurveP384 sniStrict: false --- apiVersion: traefik.containo.us/v1alpha1 kind: IngressRoute metadata: name: whoami namespace: dev spec: entryPoints: - websecure routes: - kind: Rule match: Host(`whoami.188.8.131.52.nip.io`) services: - name: whoami port: 80 tls: certResolver: le options: name: tlsoptions namespace: dev
Deploy the updated configuration and then revisit SSLLabs and regenerate the report. The new report shows the change in supported protocols and key exchange algorithms.
To boost your score to A+, use Traefik Middleware to add security headers as described in the Traefik documentation.
apiVersion: traefik.containo.us/v1alpha1 kind: Middleware metadata: name: security namespace: dev spec: headers: frameDeny: true sslRedirect: true browserXssFilter: true contentTypeNosniff: true stsIncludeSubdomains: true stsPreload: true stsSeconds: 31536000 --- apiVersion: traefik.containo.us/v1alpha1 kind: IngressRoute metadata: name: whoami namespace: dev spec: entryPoints: - websecure routes: - kind: Rule match: Host(`whoami.184.108.40.206.nip.io`) services: - name: whoami port: 80 middlewares: - name: security tls: certResolver: le options: name: tlsoptions namespace: dev
Apply this configuration to create the Middleware and update the IngressRoute, and then generate a new report from SSLLabs. The configuration now reflects the highest standards in TLS security.
In the section above, Traefik Proxy handles TLS, But there are scenarios where your application handles it instead. In such cases, Traefik Proxy must not terminate the TLS connection. Instead, it must forward the request to the end application. This is known as TLS-passthrough.
The passthrough configuration needs a TCP route instead of an HTTP route. The route can be applied to the same entrypoint and uses an IngressRouteTCP resource instead of an IngressRoute resource.
apiVersion: traefik.containo.us/v1alpha1 kind: IngressRouteTCP metadata: name: whoami spec: entryPoints: - websecure routes: - match: HostSNI(`*`) kind: Rule services: - name: whoami port: 80 tls: passthrough: true
whoami application does not handle TLS traffic, so if you deploy this route, your browser will attempt to make a TLS connection to a plaintext endpoint and will generate an error.
This article covered various Traefik Proxy configurations for serving HTTPS on Kubernetes. It works out-of-the-box with Let's Encrypt, taking care of all TLS certificate management. Traefik Proxy also provides all the necessary options for users who want to do TLS certificate management manually or via the deployed application.