Introduction

Traditionnellement, et principalement dans le monde du web, on entend souvent le mot TLS qui correspond au protocole qui vient chiffrer la connexion et prouver l'identité d'un serveur au client à l'aide d'un certificat de type X.509. Le client, quant à lui, sera en mesure de s'authentifier à travers une page de connexion (nom d'utilisateur et mot de passe).

Mais on peut aussi adopter une authentification côté client à l'aide d'un certificat. C'est ce que l'on appelle le mutual TLS (ou mTLS). On est donc dans un cas où le client et le serveur vont s'authentifier en même temps grâce à des certificats sans avoir besoin de passer par une mire d'authentification gérée par la couche application du serveur.

Ce mode d'authentification est très intéressant pour accéder à des sites ou applications de manière (très) sécurisée, il possède néanmoins un inconvénient majeur : le fait de devoir installer le certificat client sur l'ensemble de vos appareils (navigateur, mobile, etc.) dans le cas d'un site web.

Dans la suite de cet article, nous verrons comment configurer l'authentification du client par le serveur pour protéger le tableau de bord Traefik, Grafana et Prometheus. En effet, celle du serveur par le client est assuré par la génération de certificats par Let's encrypt.

Génération des certificats

Pour configurer le mTLS, il est nécessaire de générer plusieurs certificats auto-signés.

Tout d'abord, il faut créer notre autorité de certification (CA), son rôle sera de signer numériquement le certificat du client et sera porté par la suite par Traefik pour accorder au non l'accès.

Toutes les commandes ci-dessous utilise la commande openssl qui est un pré-requis indispensable pour ce type de manipulation.

De plus, les limites de temps des certificats (paramètre -days) sont arbitraires, elles peuvent être modifiées sans générer d'erreur.

mkdir ca
# Génération d'une clé privée
openssl genrsa -aes256 -out ca/ca.key 4096
# Génération du certificat racine CA
openssl req -new -x509 -sha256 -days 1095 -key ca/ca.key -out ca/ca.crt

Il ne faut pas oublier de remplir les champs demandés et initialiser une passphrase afin de rendre la création de certificat valide.

On passe maintenant à la partie client. On crée une demande de signature de certificat appelé CSR, qui contient l'ensemble des informations nécessaires afin de générer le certificat du client qui sera signé par l'autorité de certification (certificat CA racine).

mkdir client
openssl genrsa -out client/client.key 4096
# Génération du Certificate Signing Request (CSR)
openssl req -new -key client/client.key -sha256 -out client/client.csr
# Génération du certficat du client
openssl x509 -req -days 365 -sha256 -in client/client.csr -CA ca/ca.crt -CAkey ca/ca.key -set_serial 1 -out client/client.crt
# Génération du .p12
openssl pkcs12 -export -clcerts -in client/client.crt -inkey client/client.key -out client/client.p12

On peut vérifier la bonne génération des certificats .crt et .p12 avec les commandes suivantes :

# Pour le CRT
openssl verify -CAfile ca/ca.crt client/client.crt
# Pour le .p12
openssl pkcs12 -in client/client.p12 -noout -info

On dispose donc de l'ensemble des éléments pour configurer Traefik.

Configuration de Traefik

Avant de commencer

L'ensemble des pré-requis et la configuration de Traefik, Grafana et Prometheus est décrite dans l'article précédent. Il peut être intéressant de le lire car la suite se concentrera uniquement sur la configuration du mTLS.

Allons-y !

Le code du projet à cloner est disponible ci-dessous via mon compte Github.

https://github.com/axinorm/traefik-mtls

Pour configurer le mTLS, on utilise un fichier de configuration dynamique dans Traefik :

providers:
  ...
  file:
    filename: "/dynamic-conf.yml"

Ce fichier contient l'initialisation par défaut d'une authentification client avec un certificat :

tls:
  options:
    default:
      clientAuth:
        caFiles:
          - /ca.crt
        clientAuthType: RequireAndVerifyClientCert

Dans le cas du RequireAndVerifyClientCert, Traefik va vérifier que le client possède bien un certificat et qu'il a bien été signé par l'autorité de certification ca.crtqui lui est monté dans la configuration.

D'autres valeurs sont possibles pour le champ clientAuthType en suivant la documentation officielle.

Il faut déplacer le ca.crt précédemment généré dans le dossier du projet afin qu'il soit disponible dans le conteneur Traefik.

    volumes:
      ...
      - ./ca.crt:/ca.crt:ro
      ...

Avant de lancer le docker-compose, il faut installer notre certificat client .p12, c'est ce que nous allons faire dans la suite de cet article.

Installation du certificat client dans un navigateur

Pour l'installation du certificat, je vais prendre l'exemple du navigateur Firefox (version 81), vous pouvez bien sûr prendre un autre navigateur, mais les réglages seront différents.

Tout d'abord, il faut aller dans le menu des Préférences, chercher le mot "Certificat" et cliquer sur le bouton Afficher les certificats.... Une fois dans l'onglet Vos certificats, on peut cliquer sur Importer... et sélectionner notre fichier .p12.

certificat-firefox

Lancement du docker-compose

Une fois l'ensemble des pré-requis du README.mdréalisé, il ne reste plus qu'à lancer la commande suivante :

docker-compose up -d

Il est maintenant possible d'accéder via votre navigateur à l'url précédemment défini par la variable TM_URL_TRAEFIK avec le sous-domaine admin et en ajoutant /prometheus, /traefik ou /grafana en fonction du service désiré.

Dès lors que l'on tente d'accéder à cette url, une fenêtre secondaire s'ouvre :

certificat-confirmation

Avec notre certificat et l'ensemble des informations que l'on a préalablement complétées. Une fois que l'on a cliqué sur le bouton OK, le site s'ouvre.

dashboard-grafana

Avec ici comme exemple le tableau de bord de Grafana.

L'autorité de certification a donc bien reconnu notre certificat client et nous accorde l'accès au site désiré.

Conclusion

Bien que contraignante, l'authentification mTLS se révèle très intéressante pour exposer des services sensibles sur internet et est beaucoup plus sûre qu'un simple couple utilisateur/mot de passe. Je l'utilise personnellement pour mes services de supervision.