Catégories
Docker Tut's Linux

Certificat wildcard Traefik avec Let’s Encrypt

Vous allez découvrir dans cet article la génération d’un certificat wildcard Traefik fourni gratuitement par Let’s Encrypt. Avoir un certificat par service ou sous-domaine c’est bien, mais pourquoi pas exploiter la fonctionnalité wildcard permettant de générer un unique certificat pour tout les sous-domaines ?

Importante mise à jour de l’article par ldez au 15/07/2020 – une nouvelle fois, un grand merci !!


Objectif : Configurer Traefik pour obtenir un certificat wildcard via Let’s Encrypt pour tous vous services.

Environnement : Debian 10.8 (buster), Docker 19.03.x, docker-compose 1.28.x, Traefik 2.4

Cet article implique une modification côté zone DNS. Assurez-vous d’avoir vos identifiants quant à l’hébergement de votre domaine, y compris les droits nécessaires pour ajouter des enregistrements et générer des clés API.

Pour ma part, j’utilise le fournisseur « Gandi » avec la fonctionnalité « LiveDNS ». La procédure sera similaire chez d’autres fournisseurs mais pas en revu dans cet article.

Les documentations officielles de Let’s Encrypt et Traefik sont les sources de cet article.

Préparation du DNS

Plusieurs moyens de vérification sont possibles quant à la génération d’un certificat wildcard : TLS, HTTP ou encore DNS. Des API sont fournies par les hébergeurs, qui seront notamment utilisées par Traefik et l’outil lego (Implémentation de Let’s Encrypt pour les outils en Go).

Vous devez créer les enregistrements nécessaires de type « A » pour vos services. Lorsque c’est terminé, il est temps de générer une clé d’authentification API auprès de votre hébergeur. Si comme moi vous êtes chez Gandi, connectez-vous sur l’adresse « account.gandi.net« , dirigez-vous dans l’onglet « Security » et générez une « Production API key« . Gardez bien cette clé, si vous la perdez, vous devrez la regénérer.

Configurations pour Docker et Traefik

J’utiliserai le dossier /opt/docker/dc pour y stocker mes fichiers docker-compose et autres fichiers de configuration. Créons le nécessaire en terme de dossier et de fichiers :

mkdir -p /opt/docker/dc/{conf,logs}
mkdir -p /opt/docker/dc/conf/traefikdynamic

touch /opt/docker/dc/conf/acme.json
chmod 0600 /opt/docker/dc/conf/acme.json

touch /opt/docker/dc/logs/traefik.log
touch /opt/docker/dc/conf/traefik.yml
touch /opt/docker/dc/conf/traefikdynamic/dynamic.yml

Vous trouverez les sources sur GitHub à cette adresse.

Vous pouvez utiliser soit les fichiers .yml ou les fichiers .toml pour Traefik, mais pas les deux types en même temps. Le dépôt est fait de sorte à ce que vous puissiez récupérer directement les fichiers, prêt à l’emploi.

L’exemple ci-dessous est dit « configuration statique », à savoir l’utilisation de labels dans le fichier docker-compose. Ci-dessous le fichier docker-compose.yml (j’utilise les fichiers .yml pour Traefik)

---
version: '3.6'
services:
  traefik:
    container_name: traefik
    image: traefik:livarot
    restart: unless-stopped
    environment:
      - "GANDIV5_API_KEY=<INSERT-WITHOUT-HOOK>"
    ports:
      - 80:80
      - 443:443
      - 8080:8080
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./conf/traefik.yml:/etc/traefik/traefik.yml:ro
      - ./conf/traefikdynamic:/etc/traefik/dynamic:ro
      - ./conf/acme.json:/acme.json
      - ./logs/traefik.log:/etc/traefik/applog.log
    labels:
      traefik.enable: true
      traefik.http.routers.traefik-secure.entrypoints: websecure
      traefik.http.routers.traefik-secure.rule: Host(`traefik.domain.local`)
      traefik.http.routers.traefik-secure.middlewares: [email protected]
      traefik.http.routers.traefik-secure.tls: true
      traefik.http.routers.traefik-secure.tls.certresolver: letsencrypt
      traefik.http.routers.traefik-secure.tls.domains[0].main: domain.local
      traefik.http.routers.traefik-secure.tls.domains[0].sans: *.domain.local
      traefik.http.routers.traefik-secure.service: [email protected]

  portainer:
    container_name: portainer
    image: portainer/portainer-ce:2.1.1
    restart: unless-stopped
    depends_on:
      - traefik
    command: -H unix:///var/run/docker.sock
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - dataportainer:/data
    labels:
      traefik.enable: true
      traefik.http.routers.portainer.entrypoints: websecure
      traefik.http.routers.portainer.rule: Host(`portainer.domain.local`)
      traefik.http.routers.portainer.middlewares: [email protected]
      traefik.http.routers.portainer.tls: true

volumes:
  dataportainer:

fichier conf/traefik.yml

---
global:
  sendAnonymousUsage: false
  checkNewVersion: false
  #insecureSNI: false

api:
  #insecure: true
  dashboard: true
  #debug: true

log:
  filePath: "/etc/traefik/applog.log"
  level: INFO

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

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

certificatesResolvers:
  letsencrypt:
    acme:
      email: [email protected]
#      caServer: https://acme-staging-v02.api.letsencrypt.org/directory
      caServer: https://acme-v02.api.letsencrypt.org/directory
      storage: acme.json
      keyType: EC256
      dnsChallenge:
        provider: gandiv5
        resolvers:
          - "1.1.1.1:53"
          - "8.8.8.8:53"

fichier conf/traefik_dynamic.yml

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

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
        sslRedirect: true
        sslForceHost: true
        stsPreload: true
        customFrameOptionsValue: SAMEORIGIN
        referrerPolicy: "same-origin"
        featurePolicy: "camera 'none'; microphone 'none'; payment 'none'; usb 'none'; vr 'none'; vibrate 'self';"
        stsSeconds: 315360000
        hostsProxyHeaders:
          - "X-Forwarded-Host"

J’attire votre attention dans le traefik.yml : il y a deux lignes caServer, pointant vers des serveurs Let’s Encrypt. Pendant vos tests, pour éviter un blocage et un bannissement du service, utilisez uniquement la ligne « caServer … acme-staging« . Lorsque vos tests seront validés (certificats correctement récupérés et générés), vous pourrez commenter la ligne « caServer … acme-staging » et reprendre « caServer … acme-v02« .

En bref :

  • Le fichier docker-compose comporte la clé API précédemment générée, dans une variable d’environnement pour Traefik.
  • Le fichier acme.json est toujours présent avec les droits requis
  • Les labels TLS pour les services sont beaucoup plus courts et simple ! Tout se trouve dans la configuration de Traefik.

Chaque service que vous ajouterez dans votre docker-compose.yml devra comporter ces labels :

    labels:
      traefik.enable: true
      traefik.http.routers.SERVICENAME.entrypoints: websecure
      traefik.http.routers.SERVICENAME.rule: Host(`SERVICENAME.domain.local`)
      traefik.http.routers.SERVICENAME.middlewares: [email protected]
      traefik.http.routers.SERVICENAME.tls: true

Le fichier acme.json doit maintenant comporter quelques lignes pour votre certificat.

Avec cette configuration, vos services seront maintenant derrière Traefik et bénéficieront des options TLS.

2 réponses sur « Certificat wildcard Traefik avec Let’s Encrypt »

Bonjour,
J’ai lu avec beaucoup d’intérêt votre tuto et je compte m’en inspirer pour passer à la version 2 de Traefik. J’avoue que j’ai beaucoup de mal avec cette dernière. J’aurai toutefois une question: comme j’utilise plusieurs domaines (domain1.net, domain2.org, …) est ce qu’il serait possible d’utiliser votre configuration pour que chacun d’eux ait un certificat wildcard sachant qu’ils sont tous chez gandi.net.
Cordialement

bonjour,
j’ai inversé dans la config ces lignes

traefik.http.routers.traefik-secure.tls.domains[0].main: domain.local
traefik.http.routers.traefik-secure.tls.domains[0].sans: « *.domain.local »
par
traefik.http.routers.traefik-secure.tls.domains[0].main: « *.domain.local »
traefik.http.routers.traefik-secure.tls.domains[0].sans: « domain.local »

car cela ne fonctionnait pas, la c’est ok dans ce sens, il me reste un problème sur l’authentification file

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *