HTTPS on Kubernetes using Traefik Proxy | Traefik Labs

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 20.115.56.189 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.
  • The kubectl command-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

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.

Deploy application

Traefik Proxy handles requests using web and webscure entrypoints. HTTPS is enabled by using the webscure entrypoint. Create a whoami Kubernetes IngressRoute which will listen to all incoming requests for whoami.20.115.56.189.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.20.115.56.189.nip.io`)
    services:
    - name: whoami
      port: 80

Deploy the whoami application, service, and the IngressRoute. You can find the whoami.yaml file here.

Deploy the  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.20.115.56.189.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 command.

$ curl -k -vI https://whoami.20.115.56.189.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.

Manual certificates

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.

Self-signed certificates

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 CN and 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.20.115.56.189.nip.io
[ req_ext ]
subjectAltName = @alt_names
[ alt_names ]
DNS.1 = whoami.20.115.56.189.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'
-----

Configure IngressRoute

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

Update the IngressRoute and reference the Secret in the tls.secretName attribute.

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.20.115.56.189.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.

Default certificates

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"
      - "--certificatesresolvers.le.acme.email=youremmail@gmail.com"
      - "--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

Configure IngressRoute

Although you can configure Traefik Proxy to use multiple certificatesresolvers,  an 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.20.115.56.189.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.

TLS options

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 whoami IngressRoute.

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.20.115.56.189.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.20.115.56.189.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.

HTTPS passthrough

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 

The 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.

Summing up

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.


This is a companion discussion topic for the original entry at https://traefik.io/blog/https-on-kubernetes-using-traefik-proxy/