Pris dans le Traefik
Un premier post pour aborder l’incourtournable Traefik en reverse proxy http/tcp pour Docker.
Installation
On passe l’installation de Docker CE et Docker-Compose qui ne présente pas de problème particulier. L’ensemble des fichiers de configurations sera stocké dans l’arborescence suivante:
1/opt
2├── traefik
3│ ├── config
4│ │ ├── acme.json
5│ │ ├── dynamic-conf
6│ │ │ ├── dashboard.toml
7│ │ │ ├── tlsredir.toml
8│ │ │ ├── tls.toml
9│ │ └── traefik.toml
10│ └── docker-compose.yml
On commence par un docker-compose simple utilisant un bridge avec un subnet dédié:
1 sudo docker network create --driver=bridge --subnet=172.19.0.0/24 traefik_lan
1version: '3'
2
3services:
4 reverse-proxy:
5 image: traefik:v2.2
6 restart: unless-stopped
7 ports:
8 - "80:80"
9 - "443:443"
10 expose:
11 - "8080"
12 networks:
13 - traefik_lan
14 volumes:
15 - /var/run/docker.sock:/var/run/docker.sock:ro
16 - /opt/traefik/config:/etc/traefik:ro
17 - /opt/traefik/config/acme.json:/acme.json
18networks:
19 traefik_lan:
20 external: true
on compléte avec un fichier traefik.toml utilisant le mode dynamique (providers.file) qui permet de modifier la configuration sans relancer le conteneur.
L’opération est rendue possible grace au volume en bind mount /opt/traefik/config:/etc/traefik
On retrouve également la déclaration:
- des entryPoints en http / https
- la configuration Let’s Encrypt pour un challenge TLS
- du formatage des logs.
1[api]
2 dashboard = true
3
4[providers]
5 [providers.docker]
6 exposedByDefault = false
7
8 [providers.file]
9 directory = "/etc/traefik/dynamic-conf"
10 watch = true
11
12[entryPoints]
13 [entryPoints.websecure]
14 address = ":443"
15
16 [entryPoints.webinsecure]
17 address = ":80"
18
19
20[certificatesResolvers.letsencrypt.acme]
21 email = "my-email@domain.tld"
22 storage = "acme.json"
23 [certificatesResolvers.letsencrypt.acme.tlsChallenge]
24
25
26[accessLog]
27 format = "json"
28 [accessLog.fields]
29 defaultMode = "drop"
30 [accessLog.fields.names]
31 "ClientAddr" = "keep"
32 "RequestAddr" = "keep"
33 "RequestMethod" = "keep"
34 "RequestPath" = "keep"
35 "DownstreamStatus" = "keep"
On configure l’accés au dashboard en mode secure via la configuration dynamique (/opt/traefik/config/dynamic-conf/dashboard.toml):
Au passage, on ajoute quelques restrictions:
- une whitelist (ça s’appelle encore comme ça chez Traefik) sur mon subnet local
- une http basic auth (à générer avec un
htpasswd -nb user password)
1[http.routers.api]
2 rule = "Host(`traefik.domain.tld`)"
3 entrypoints = ["webinsecure"]
4 service = "api@internal"
5 middlewares = ["tlsredir@file"]
6
7[http.routers.api-secure]
8 rule = "Host(`traefik.domain.tld`)"
9 entrypoints = ["websecure"]
10 service = "api@internal"
11 middlewares = ["secured"]
12 [http.routers.api-secure.tls]
13 certResolver = "letsencrypt"
14
15[http.middlewares]
16 [http.middlewares.secured.chain]
17 middlewares = ["known-ips", "auth-users"]
18
19[http.middlewares.auth-users.basicAuth]
20 users = ["admin:$apr1$ZzA4BECk$dfdfsdfstCZN6.XH0lX1"]
21
22[http.middlewares.known-ips.ipWhiteList]
23 sourceRange = ["192.168.0.O/24"]
On force également l’accès en https (/opt/traefik/config/dynamic-conf/tlsredir.toml):
1[http.middlewares]
2 [http.middlewares.tlsredir.redirectScheme]
3 scheme = "https"
4 permanent = true
et pour finir, on affine la configuration TLS pour tenter le rang A+ sur SSL Labs (/opt/traefik/config/dynamic-conf/tls.toml)
1[tls]
2 [tls.options]
3 [tls.options.default]
4 minVersion = "VersionTLS12"
5 sniStrict = true
6 cipherSuites = [
7 "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
8 "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
9 ]
10 curvePreferences = ["CurveP521","CurveP384"]
La configuration de Traefik est maintenant terminée, il est temps de démarrer quelques services ….pour cela, il suffit d’ajouter un bloc de labels dans leurs docker-compose:
- la ligne
- "traefik.docker.network=traefik_lan"est nécéssaire si vous avez plusieurs networks déclarés dans votre docker compose
1labels:
2 - "traefik.enable=true"
3 - "traefik.docker.network=traefik_lan"
4 - "traefik.http.routers.<my-app>.rule=Host(`my-app.domain.tld`)"
5 - "traefik.http.routers.<my-app>notls.entrypoints=webinsecure"
6 - "traefik.http.routers.<my-app>enotls.middlewares=tlsredir@file"
7 - "traefik.http.routers.<my-app>.rule=Host(`my-app.domain.tld`)"
8 - "traefik.http.routers.<my-app>.entrypoints=websecure"
9 - "traefik.http.routers.<my-app>e.tls=true"
10 - "traefik.http.routers.<my-app>.tls.certresolver=letsencrypt"
Remerciements
Un grand merci à Hugo (pas le CMS!) et aux blogs: