Deploy Traefik on Kubernetes with Wildcard TLS Certs
In the first part of this series, I talked about the motivations behind my choice of Traefik as the Ingress Controller for my Kubernetes cluster.
In this 2nd part of the series, I'll walk you through how you can get your own Traefik deployment up and running without having to dig through much as a single page of the Traefik documentation.
I've dug through the documentation so you don't have to!
With all the chitter chatter aside, let's jump right in to deploying Traefik on your Kubernetes cluster. This assumes that you already have a Kubernetes cluster set up. If you haven't already done so, you may refer to my previous post on how you can set one up with k3s.
With Helm
Helm installation is as easy as running 3 commands. If you haven't installed helm yet, install the tool with brew install helm
and follow their instructions on how to install it on your cluster.
helm repo add traefik https://helm.traefik.io/traefik
helm repo update
helm install traefik traefik/traefik
I am not a big fan of Helm myself so I have not tried it on my cluster, but I'm putting it here nonetheless for those who favor Helm and for the sake of completeness.
With plain yaml
Personally, I'm a huge fan of explicitness, especially when it comes to my cluster. Hence, I've always opted for plain Kubernetes yaml manifests so that I have full control over each deployment.
Here are my personal deployment files, but simplified in the following ways:
- single-replica deployment
TLS-ALPN-01
challenge instead ofDNS-01
challenge (if you don't need wildcard TLS certs)
Using the manifests here would create a traefik-system
namespace and deploy Traefik in it. To use them, save each of them in a file, and apply them to your cluster with kubectl apply -f <filename.yaml>
.
When using the above manifests, be sure to change the following according to your infrastructure:
spec.loadBalancerIP
field intraefik-service.yaml
to your cluster's public IP address. This assumes you already have a load balancer service on your cluster. If you haven't, I'd recommend that you check out MetalLB.certificateResolves.default.acme.email
field intraefik-configmap.yaml
to your email address.
It need not be a functional email address but it would make things easier as Let's Encrypt would notify you by email when your certificate is nearing expirynfs.server
field intraefik-pv-pvc.yaml
to your NFS server hostname or IP address.nfs.path
field intraefik-pv-pvc.yaml
to your NFS server path dedicated to storing Traefik's TLS certs.
Some notes about my Deployment specification for Traefik:
- Traefik image used here of version
2.4.5
RollingUpdate
strategy allows for zero-downtime updates for the event when you need to upgrade Traefik to a newer versionNET_BIND_SERVICE
permissions are required for the Traefik Pod to bind to privileged ports such as80
and443
on the node
Configuring Traefik for Kubernetes IngressRoute provider
Typically for ingress controllers, one will apply controller-specific configuration via annotations
on the Ingress object. I found this to be rather clunky such as in the event where one has to specify complex data structures like maps or lists in string format as an annotation, so I've opted to use Traefik's custom resource definition known as the IngressRoute to specify ingress rules.
I like how IngressRoutes are more expressive and generally much neater than just using annotations, although I'm aware that this essentially locks me in to using Traefik for all my apps, but I figured it's not too difficult to migrate back to plain Ingress objects one day should there be a need to as I'm not running business-critical apps.
Shown below are the CRDs and RBACs for my Traefik deployment. You are advised to check their docs for more up-to-date versions of these definitions.
Deploying an example app
To test app connectivity, TLS certificate validity and load-balancing behaviour, you may use Traefik's official test image whoami
.
Apply the following manifests to your cluster:
Note: Replace<your-domain-name>
inspec.routes[0].match
ofwhoami-ingressroute.yaml
with your domain name.
Deploying the manifests above will deploy 3-replicas of the whoami
image, and also trigger traefik to request a certificate for whoami.<your-domain-name>
.
If you see certificate errors, wait a couple of minutes as Traefik may be still in the process of requesting a certificate from Let's Encrypt, and meanwhile serving with its default self-signed TLS certificates. You may monitor the progress of ACME challenges by locating the Traefik pod name and tailing the logs for it, searching specifically for the acme
keyword.
If nothing has gone horribly wrong thus far, loading the page prints the current pod name that your request has reached. Refreshing the page would ideally rotate you through all 3 whoami
pods, demonstrating the default round-robin load balancing that Traefik implements.
(Optional) Wildcard TLS Certificates
Although there's some debate in the community about potential security concerns of TLS certificates, in my opinion, there are several non-negligible reasons as to why one should consider using wildcard TLS certificates.
Single certificate for all subdomains
Wildcard TLS certificates would help simplify TLS certificate management for your cluster immensely by allowing all subdomains to share a single TLS certificate.
This means, if you're segregating your application domains by using subdomains (which you should be) you do not need to request a new certificate per application. This essentially gets rid of the delay between your application's first deployment and its final availability via HTTPS.
Subdomain obfuscation
Another added benefit of wildcard TLS certificates is subdomain obfuscation. With the traditional method of 1 TLS certificate per subdomain, the presence of your subdomains is exposed to the public via the Certificate Transparency Logs as I briefly demonstrated above with my domain ikrs.link
.
Using a wildcard certificate hides your subdomains from these public logs and all that a malicious actor can glean is that you host services under the your domain name over TLS, but do not know which subdomains they're on. Though obfuscation is not the same as security itself, not giving away your subdomains upfront is already a plus to me.
Configuring Traefik to request wildcard TLS certificates
To obtain wildcard TLS certificates, one would need to complete the DNS-01
challenge. To do that, you'll need to make 2 changes to Traefik:
Add the configuration keys in place of tlsChallenge:
in the static configuration ConfigMap.
dnsChallenge:
provider: namecheap
Depending on your DNS provider, add the required environment variables to your Traefik deployment. Traefik supports many DNS providers such as Cloudflare or Namecheap to name a few, hence it's very likely that your DNS provider is supported. Check their documentation to find out if your provider is supported.
Deploy a Kubernetes containing your provider's credentials for Traefik to pick up.
Paste the env
section underspec.template.spec.containers[0]
of traefik-deployment.yaml
. In this example, I assume that you're using the Namecheap DNS provider.
Upon applying traefik-deployment.yaml
Traefik would delete and recreate the Traefik pod and if you already have an IngressRoute defined that requires a cert but don't already have a cert, Traefik will start requesting for a cert from Let's Encrypt with the DNS-01 challenge.
And just like that, you have a working TLS-enabled reverse proxy!
What's next
In the next part of this series, I will be talking about cert-manager
and how it can help further simplify TLS certificate management. See you in a week or two!