Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentes Révision précédente
Prochaine révision
Révision précédente
technique:docker:good_practices:traefik [2021/09/02 22:12] qduchemitechnique:docker:good_practices:traefik [2022/09/23 10:21] (Version actuelle) – modification externe 127.0.0.1
Ligne 1: Ligne 1:
 +{{indexmenu_n>20}}
 +# Rendre un service accessible publiquement
  
 +## Préambule
 +
 +Quand un conteneur Docker doit être accessible depuis l'extérieur de la machine, il y a deux solutions :
 +
 +* Mapper un port de l'hôte sur un port du conteneur
 +* Utiliser [[technique:tech_team:traefik|Traefik]]
 +
 +<bootnote important>
 +La règle générale est la suivante : on utilise un mapping de port pour les services **non-web** (*e.g.* LDAP, mail, SFTP...) et Traefik pour tous les services web. Une explication se trouve sur la [[technique:tech_team:traefik|page dédiée à Traefik]].</bootnote>
 +
 +## Mapping de port
 +
 +C'est la technique la plus simple. Supposons qu'un conteneur écoute sur son port interne 8080, et qu'on veuille le rendre accessible depuis l'extérieur. On va choisir arbitrairement un port de l'hôte que l'on va mapper dessus, par exemple :
 +
 +```yaml
 +services:
 +  example:
 +    image: <image>
 +    ports:
 +      - 2000:8080
 +```
 +
 +Dans cet exemple, tout ce qui arrive sur le port `2000` de la machine sera redirigé sur le port `8080` du conteneur.
 +
 +<bootnote warning>Par contre, pour tout ce qui concerne la gestion de TLS ou d'autres fonctionnalités de Traefik, on n'en profite pas, car on ne passe pas du tout par lui.</bootnote>
 +
 +## Utiliser Traefik
 +
 +Pour les services web, on préfère largement passer par Traefik, car on pourra utiliser un port standard (`80` ou `443`) et profiter de toutes ses fonctionnalités (HTTPS automatique, etc).
 +
 +On configure le fait de router vers un conteneur grâce aux [labels Docker](https://docs.docker.com/config/labels-custom-metadata/). Voici un extrait commenté permettant de router toutes les requêtes arrivant sur Traefik à destination de `app.picasoft.net` vers le conteneur `exemple`, sur son port `8080` :
 +
 +```yaml
 +networks:
 +  proxy:
 +    external: true
 +
 +services:
 +  exemple:
 +    container_name: example
 +    networks:
 +      - proxy
 +    labels:
 +      # Traefik va prendre ce conteneur en compte
 +      traefik.enable: true
 +      # websecure correspond au port 443 de la machine (config Traefik)
 +      # Remplacer <exemple> par le nom du conteneur
 +      traefik.http.routers.<exemple>.entrypoints: websecure
 +      # Il redirigera vers ce port, exposé par le conteneur
 +      # Remplacer <exemple> par le nom du conteneur
 +      # Remplacer app.picasoft.net par l'URL souhaitée
 +      traefik.http.routers.<exemple>.rule: Host(`app.picasoft.net`)
 +      # Lorsque l'utilisateur consulte cette URL
 +      # Remplacer <exemple> par le nom du conteneur
 +      # Remplacer 8080 par le port du service
 +      traefik.http.services.<exemple>.loadbalancer.server.port: 8080
 +```
 +
 +<bootnote critical>Il est essentiel que le conteneur soit dans le même réseau que Traefik, qui est fixé à `proxy` ! C'est le sens des directives `networks`.</bootnote>
 +
 +`websecure` désigne, dans la configuration Traefik, le port 443. Tout ce qui arrive vers Traefik est redirigé vers cet entrypoint, il faut donc se coller dessus.
 +
 +<bootnote>Il est possible d'être plus fin sur l'URL à laquelle répondra le conteneur, et même d'utiliser des chemins spécifiques ou des expressions régulières. Voir [la documentation officielle](https://doc.traefik.io/traefik/v2.0/routing/routers/#rule).</bootnote>
 +
 +## Sécuriser une sous-partie du service par authentification
 +
 +Il y a pas mal de cas d'utilisation où une sous-partie d'un site doit être sécurisée par authentification :
 +
 +- La partie `/admin` d'un service exposé sur internet mais sans authentification intégrée au service
 +- La partie `/metrics` d'un service qui doit être accessible à [[technique:adminsys:monitoring:metrologie:victoriametrics|la solution de monitoring]] mais pas aux internautes...
 +
 +La solution consiste à créer un second point d'entrée à l'aide des labels. En reprenant l'exemple de la section précédente, on rajouterait ces labels :
 +
 +```yaml
 +# Toujours le même point d'entrée : HTTPS
 +traefik.http.routers.<exemple>-metrics.entrypoints: websecure
 +# Ce point d'entrée sera sélectionné uniquement pour les requêtes
 +# vers app.picasoft.net/metrics et ses dérivés.
 +traefik.http.routers.<exemple>-metrics.rule: "Host(`app.picasoft.net`) && PathPrefix(`/metrics`)"
 +# Indique que ce point d'entrée passe par un middleware nommé <exemple>-metrics-auth et qui est
 +# configuré via les labels Docker (voir juste en dessous)
 +traefik.http.routers.<exemple>-metrics.middlewares: "<exemple>-metrics-auth@docker"
 +# Ce middleware est simplement une authentification, qui vient se mettre entre le point d'entrée
 +# et l'application.
 +traefik.http.middlewares.<exemple>-metrics-auth.basicauth.users: "test:$2y$10$7Gv5tUZC1UBsTyQs/ZTwmu0jamzBJFnNEY4SMxqdfIYfTyLBDTINm"
 +```
 +
 +La chaîne `$2y$10$7Gv5tUZC1UBsTyQs/ZTwmu0jamzBJFnNEY4SMxqdfIYfTyLBDTINm` correspond au mot de passe `test` hashé avec [bcrypt](https://fr.wikipedia.org/wiki/Bcrypt).
 +
 +<bootnote critical>
 +Pour éviter de versionner la chaîne d'identification, on préfère plutôt utiliser une variable pour le label `basicauth.users`, qui vaudra "${METRICS_AUTH}". La valeur sera placée dans un fichier `.env` sur la machine de production, sous le format suivant :
 +
 +```
 +METRICS_AUTH=test:$2y$10$7Gv5tUZC1UBsTyQs/ZTwmu0jamzBJFnNEY4SMxqdfIYfTyLBDTINm
 +```
 +
 +En effet, Docker Compose lit les fichiers `.env` et remplace les variables par leur valeur dans le fichier Compose. De plus, Git ignore les fichiers cachés par défaut, on ne risque pas de commiter les secrets par erreur. 
 +</bootnote>
 +
 +<bootnote learn>
 +Pour générer la chaîne d'authenticiation Basic Auth qui est donnée au label Traefik, on commence par définir un nom d'utilisateur (ici ''test'') et par générer un mot de passe (par exemple avec ''pwgen -sB 64''). On place ces identifiants dans le [[asso:tuto:vaultwarden|vaultwarden]].  
 +
 +On utilise ensuite la commande suivante pour générer la chaîne d'authentification qu'il faut renseigner dans le label.
 +```
 +$ echo $(htpasswd -nb USER PASSWORD)
 +USER:$apr1$4WpORg/6$.bUMzTnrDPivUXfu7.vvP0
 +```
 +</bootnote>