January 20, 2022 •
Assume you have a personal Wiki which you host yourself as a Docker container. You may want to restrict access to the wiki, so that strangers cannot access it. One, very obvious way, is of course enabling username and password checking in the software itself. Another way would be to limit network access to the wiki. In this article, we will demonstrate how to set up client certificate checking in Traefik, in order to allow access only users with a valid client certificate.
This article is going to demonstrate how to set up a Traefik provider for client certificate checking. Then, we will show how to enable this provider in a docker-compose file. For sake of simplicty, we are not digging into the details of creating client certificates, however this web-article may help How to Create a Self-signed Client Certificate with OpenSSL.
In this article we are using a recent Traefik Proxy Version 2.5.6.
We are assuming, Traefik is up and running as a Docker container. If this is not the case and / or you are new to this topic, check out the following blog article to get started: Continuous Deployment Revisited - Making Docker Containers Accessible with Traefik 2.x.
To configure providers in Traefik, we actually need to do a couple of things:
There are different types of providers, and if you have read our other blog articles about Traefik, you have come accross the
Docker provider already. This is the one, which also checks whether a Docker container is started or stopped.
For client certificate checking we will configure file based providers. Enabling them is a rather quick story. Edit your
traefik.toml file and add the following lines:
[providers] [providers.file] directory = "/providers"
If you want Traefik to monitor the directory and update provider configurations automatically upon change, you may add a
watch: true to the
[providers.file] section (with the same identation as
directory). Also, if you want only one file to be used, you may swap
filename and providing a filename of your configuration. Please see the file provider documentation for further information.
Have in mind that
filename refer to your Docker Container internal file system structure. We have created a directory
providers where we will collect all of our provider configurations to keep everything neat and clean.
Now creating the provider is as simple as creating a file. In this case,
The name of the provider will be
client (see lines 2 and 3, provider Namespaces are explained in the provider namespace documentation). The file name is not relevant!
[tls.options] [tls.options.client] [tls.options.client.clientAuth] caFiles = ["/certs/colamda-ca.crt"] clientAuthType = "RequireAndVerifyClientCert"
Please note line 4, where
caFiles is assigned a list of files:
caFilesis assigned a list of files. If your ca-certificate expires, sometime in the future, you may add another ca-certificate ahead of time to prepare for a transition and then remove the old ca-certificate afterwards.
There are different kinds of checks you may enable in
clientAuthType . Please check the client authentication documentation for further details.
RequireAndVerifyClientCert does pretty much what is advertised: It requires a client certificate and also checks whether a given client-certificate is valid, which is the strictest setting available.
All in all, the below docker-compose file does not vary much from the ones in our other examples. Notice lines 19-20, where we have added volume mounts for the provider and certificate directory. In order to keep the directory structure clean, we have moved the
acme.json files to a separate directory, too (see line 17 and 18).
version: '3' services: traefik: image: traefik:v2.5.6 container_name: traefik hostname: traefik restart: always ports: - "80:80" - "443:443" networks: - traefik_proxy volumes: - /var/run/docker.sock:/var/run/docker.sock - ./conf/traefik/traefik.toml:/traefik.toml - ./conf/traefik/acme.json:/acme.json - ./conf/providers:/providers - ./conf/certs:/certs networks: traefiknet: driver: bridge traefik_proxy: external: name: traefik_proxy
The following docker-compose file is a vastly simplified example. Most of the labels used were discussed in the blog article on Continuous Deployment Revisited - Making Docker Containers Accessible with Traefik 2.x.
The only thing worth mentioning here is line 20:
traefik.http.routers.wiki-web-secure.tls.options: "client@file", where we are adding a
file provider with the name
client as a router. This is it: One line.
version: '3' services: wiki: image: <SOME APPLICATION, e.g. WIKI, DOCKER IMAGE> labels: traefik.enable: "true" traefik.docker.network: "traefik_proxy" traefik.http.routers.wiki-web.rule: "Host(`<YOUR DOMAIN>`)" traefik.http.routers.wiki-web.entrypoints: "web" traefik.http.routers.wiki-web.middlewares: "wiki-https" traefik.http.middlewares.wiki-https.redirectscheme.scheme: "https" traefik.http.routers.wiki-web-secure.rule: "Host(`<YOUR DOMAIN>`)" traefik.http.routers.wiki-web-secure.entrypoints: "web-secure" traefik.http.routers.wiki-web-secure.tls.certresolver: "letsencrypt" traefik.http.routers.wiki-web-secure.middlewares: "wiki-gzip" traefik.http.routers.wiki-web-secure.service: "wiki-web" traefik.http.middlewares.wiki-gzip.compress: "true" traefik.http.services.wiki-web.loadbalancer.server.port: "8080" traefik.http.routers.wiki-web-secure.tls.options: "client@file" networks: - traefik_proxy networks: traefik_proxy: external: name: traefik_proxy
Okay, now all the pieces are in place! If you try and access your application, access should be denied unless you install a client certificate which matches one of the certificate authority certificates, installed in your Traefik instance. Typically client certificates are installed in your application (e.g. browser) or operating system as a system-wide setting.