L'objectif de cet article est de fournir les fichiers de configuration pour faire fonctionner Traefik avec une configuration TLS personnalisée.

Version Date Commentaires
1 05/2022 Création de l'article

Objectif : Installer et utiliser une configuration TLS personnalisée pour Traefik

Environnement : Debian 11.2 (bullseye), Docker 20.10.x, docker-compose 2.4.x, Traefik 2.6


Configuration du fichier docker-compose

Avant-propos, vous ne pouvez pas utiliser les deux types de configurations (statique et dynamique) en même temps, c'est l'un ou l'autre. Ici, je privilégie la configuration dynamique. Au besoin, vous trouverez un rappel des différents types de configuration à cette adresse.

Préparons notre fichier docker-compose.yml :

---
services:
  traefik:
    image: traefik:v2.6
    restart: unless-stopped
    ports:
      - 80:80
      - 443:443
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /etc/localtime:/etc/localtime:ro
      - /etc/timezone:/etc/timezone:ro
      - ./conf/traefik.yml:/etc/traefik/traefik.yml:ro
      - ./conf/traefikdynamic:/etc/traefik/dynamic:ro
      - ./acme.json:/etc/traefik/acme.json
      - ./logs/traefik.log:/etc/traefik/applog.log

Explications :

  • j'utilise la version de Traefik avec la v2.6
  • exposition des ports TCP 80 et 443
  • montage de plusieurs volumes : un premier fichier de configuration "traefik.yml" pour les options de base et le dossier entier pour les options dites "dynamiques". Le dossier entier est monté, les fichiers à l'intérieur le seront donc aussi.
  • le fichier "acme.json" est à créer avant tout, via un touch acme.json && chmod 0600 acme.json.

Configuration de Traefik

Pour rappel, tous les fichiers de configuration que je vous propose sont créés dans un dossier "conf". Libre à vous de placer les fichiers où vous le souhaitez, tant que vous modifiez correctement les chemins dans les configurations.

Contenu du fichier traefik.yml :

---
global:
  sendAnonymousUsage: false
  checkNewVersion: false

api:
  dashboard: true

pilot:
  dashboard: false

log:
  filePath: "/etc/traefik/applog.log"
  format: json
  level: "ERROR"

providers:
  docker:
    endpoint: unix:///var/run/docker.sock
    exposedByDefault: false
    watch: true
    swarmMode: false
  file:
    directory: "/dynamic"
    watch: true

api:
  dashboard: true
  debug: false

entryPoints:
  web:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: websecure
          scheme: https
  websecure:
    address: ":443"

certificatesResolvers:
  letsencrypt:
    acme:
      email: contact@domain.local
      caServer: https://acme-staging-v02.api.letsencrypt.org/directory
#      caServer: https://acme-v02.api.letsencrypt.org/directory
      storage: "/etc/traefik/acme.json"
      keyType: EC256
      httpChallenge:
        entryPoint: web

Ce qui est important dans ce fichier, c'est le bloc "providers" avec la définition d'un dossier "dynamic". Ce dossier est à créer en local auparavant sur votre machine pour y intégrer ensuite le fichier "traefik_dynamic.yml".

La ligne watch = true permet à Traefik de regarder les changements fourni dans les fichiers de configuration et de les appliquer une fois l'enregistrement du fichier effectué.

Les certificats sont générés à l'aide du service Let's Encrypt ; en effet, Traefik, au travers de l'outil "lego", ira lui-même générer les certificats nécessaires. Lors de vos tests, préférez utiliser le serveur "staging" qui a une limite plus haute que le serveur "acme-v02". Une fois les tests terminés, vous pouvez commenter la ligne "staging" et utiliser le serveur Let's Encrypt "acme-v02".

Le fichier de configuration secondaire (dynamique) est de même type que le "traefik.yml", la différence réside dans les paramètres. Pour rappel, le fichier "traefik.yml" contient la configuration pour le démarrage de Traefik, tandis que le fichier de configuration dynamique contient les options pour les middlewares, les routeurs et autres loadbalancers. Retrouvez ci-dessous mon fichier de configuration "traefik_dynamic.yml", dans le dossier "conf/traefikdynamic" :

---
tls:
  options:
    default:
      minVersion: VersionTLS12
      sniStrict: true
      cipherSuites:
        - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
        - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
        - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
        - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
        - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
        - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
        - TLS_AES_128_GCM_SHA256
        - TLS_AES_256_GCM_SHA384
        - TLS_CHACHA20_POLY1305_SHA256
      curvePreferences:
        - CurveP521
        - CurveP384
      alpnProtocols:
        - h2
        - http/1.1
    mintls13:
      minVersion: VersionTLS13

http:
  middlewares:
    compression:
      compress:
        excludedContentTypes:
          - text/event-stream
    security:
      headers:
        accessControlAllowMethods:
          - GET
          - OPTIONS
          - PUT
        accessControlMaxAge: 100
        addVaryHeader: true
        browserXssFilter: true
        contentTypeNosniff: true
        forceSTSHeader: true
        frameDeny: true
        stsPreload: true
        customFrameOptionsValue: SAMEORIGIN
        referrerPolicy: "origin-when-cross-origin"
        permissionsPolicy: "camera 'none'; microphone 'none'; geolocation 'none'; payment 'none';"
        stsSeconds: 315360000
        hostsProxyHeaders:
          - "X-Forwarded-Host"

Quelques explications à fournir :

  • le bloc TLS instaure toutes les options nécessaires pour avoir une configuration optimale - pour faire simple, la version minimale est le TLS 1.2 avec des algorithmes de chiffrement utilisés par les navigateurs web modernes ;
  • le bloc "HTTP" comporte 2 sous-blocs :
    - un premier middleware pour compresser certains flux sauf en cas de streaming
    - un second middleware pour toutes les sécurités relative au HTTPS (les "headers").

Les fichiers de configuration sont prêts, ne reste plus qu'à configurer les services dans votre docker-compose.yml ! Voilà ce qu'il faut saisir pour chaque service dont Traefik devra rediriger le flux :

    labels:
      traefik.enable: "true"
      traefik.http.routers.service-https.entrypoints: "websecure"
      traefik.http.routers.service-https.middlewares: "security@file, compression@file"
      traefik.http.routers.service-https.tls: "true"
      traefik.http.routers.service-https.tls.certresolver: "letsencrypt"

Tous ces labels sont à saisir pour chaque service derrière Traefik. Les middlewares security@file et compression@file viennent piocher directement les paramètres dans le fichier traefik_dynamic.yml précédemment créé.

Lorsque vos labels sont mis en place, n'oubliez pas de relancer vos conteneurs Docker (docker-compose up -d) et le tour est joué.

Si vous n'utilisez pas les labels docker, vous pouvez ajouter dans le fichier "traefikdynamic.yml" ces informations de "routeurs" et "services" à la suite des configurations TLS, dans le bloc http : (pour l'exemple, j'utiliserai le conteneur Portainer)

  services:
    sc-portainer:
      loadBalancer:
        servers:
        - url: "http://portainer:9000"
 
   routers:
     rt-portainer:
      entryPoints:
      - websecure
      middlewares:
      - security
      - compression
      service: sc-portainer
      rule: Host(`portainer.domain.local`)
      tls:
        certResolver: letsencrypt

Vous n'avez pas besoin de redémarrer les conteneurs lorsque vous faites les modifications dans le fichier "traefikdynamic.yml". Les modifications sont prises à chaud.

Partager l'article