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: