Pris dans le Traefik

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:

Sources / Docs…