Cet article explicite la génération d'un certificat SSL de type 'wildcard' généré gratuitement par Let's Encrypt. Avoir un certificat par service ou sous-domaine c'est bien, mais allons plus loin et exploitons la fonctionnalité wildcard
permettant de générer un unique certificat pour tous les sous-domaines.
Importante mise Ă jour de l'article par ldez au 15/07/2020. Une nouvelle fois, un grand merci !!
Version | Date | Commentaires |
---|---|---|
1 | 07/2020 | Création de l'article |
1.1 | 05/2022 | Reformatage de l'article |
1.2 | 07/2022 | Mise Ă jour des informations |
Objectif : Configurer Traefik pour obtenir un certificat wildcard via Let's Encrypt pour tous vous services.
Environnement : Debian 11.7
, Docker 23.x
, docker compose (plugin) 2.17.x
, Traefik 2.10
.
Contexte d'exécution :
jho@vmi866042:/srv/docker/dc$ tree
.
âââ conf
â  âââ acme.json
â  âââ traefik.yml
â  âââ traefikdynamic
â  â  âââ general.yml
â  â  âââ routersservices.yml
âââ docker-compose.yml
âââ logs
âââ traefikAccess.log
âââ traefik.log
Cet article implique une modification dans votre zone DNS. Assurez-vous d'avoir vos identifiants quant à l'accÚs au service ou serveur DNS, y compris les droits nécessaires pour ajouter des enregistrements et générer des clés API. Ici, j'utiliserai le fournisseur "Gandi" avec la fonctionnalité "LiveDNS". La procédure est similaire avec d'autres gestionnaires de service DNS, mais ne sera pas vu dans 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 au travers de l'outil lego
.
Vous devez crĂ©er les enregistrements de type "A" nĂ©cessaires pour vos services. Ensuite, gĂ©nĂ©rez 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 cette clĂ© prĂ©cieusement, si vous la perdez, vous devrez la rĂ©gĂ©nĂ©rer.
Configurations pour Docker et Traefik
J'utiliserai le dossier /opt/docker/dc
pour y stocker les fichiers YAML docker-compose et les fichiers de configuration de Traefik. Créons le nécessaire :
mkdir -p /srv/docker/dc/{conf,logs}
mkdir -p /srv/docker/dc/conf/traefikdynamicw
touch /srv/docker/dc/conf/acme.json
chmod 0600 /srv/docker/dc/conf/acme.json
touch /srv/docker/dc/logs/traefik.log /srv/docker/dc/conf/traefik.yml /srv/docker/dc/conf/traefikdynamic/dynamic.yml
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
:
---
services:
traefik:
image: traefik:2.8
restart: unless-stopped
environment:
- "GANDIV5_API_KEY=<INSERT-WITHOUT-HOOK>"
ports:
- 80:80
- 443:443
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
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.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: api@internal
portainer:
container_name: portainer
image: portainer/portainer-ce:2.14.0
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: security@file
traefik.http.routers.portainer.tls: true
volumes:
dataportainer:
Fichier conf/traefik.yml
:
---
global:
sendAnonymousUsage: false
checkNewVersion: false
api:
dashboard: true
pilot:
dashboard: false
log:
level: ERROR
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: contact@domain.local
# 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
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"
J'attire votre attention Ă propos du fichier traefik.yml
⣠: il y a deux lignes caServer
, pointant vers des serveurs Let's Encrypt. Pendant vos tests, pour éviter un bannissement auprÚs de Let's Encrypt (nombre maximal de demandes par semaine), 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". N'oubliez pas de redémarrer Traefik pour prendre en compte les modifications et régénérer les certificats "de production".
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 simples ! 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: security@file
traefik.http.routers.SERVICENAME.tls: true
Le fichier acme.json
doit maintenant comporter quelques lignes pour votre certificat. Avec cette configuration, vos services seront à présent derriÚre Traefik, seront accessibles via SSL (et utiliseront le certificat SSL wildcard), et bénéficieront des options TLS.
Sources : Traefik et Let's Encrypt