Traefik
Traefik est un logiciel permettant de faire un serveur mandataire inversé (reverse proxy) et pouvant faire de la répartition de charge (load balancer). Il est développé en Go et a la particularité de faire de la découverte automatique (toute les deux secondes par défaut) de fichiers de configurations (pas de redémarrage du service). Ceci a pour intérêt de permettre une actualisation du mandataire en agissant uniquement sur des fichiers et non le service lui-même. On peut alors imaginer une actualisation de la configuration du serveur par simple copier/coller de fichiers depuis un partage sans privilèges root par exemple.
ATTENTION
L'application Traefik évolue très rapidement. Le présent document traite de la version 2 de Traefik, les fichiers de configurations n'ont rien à voir.Schéma fonctionnel
Traefik traite les requêtes des clients en les faisant passer dans divers fonctions selon le schéma suivant:
- EntryPoint : Permet la déclaration des ports d'entrés de Traefik. Habituellement 80 et 443
- Routers : Permet la déclaration de l'URL pour contacter le service
- Middlewares : Permet la modification du comportement de l'appel. Ex: Ajout d'une authentification
- Service : Permet la déclaration du serveur qui héberge le service
Installation
Traefik n'est pas présent dans les dépôts Debian Buster. Il va donc falloir le télécharger depuis son dépôt Git.
wget https://github.com/containous/traefik/releases/download/v2.2.1/traefik_v2.2.1_linux_amd64.tar.gz -P /tmp/ mkdir -p /opt/traefik/{config/vhosts,tls,passwd,logs} tar xzvf /tmp/traefik_v2.2.1_linux_amd64.tar.gz -C /opt/traefik/
Création de l'utilisateur du service
useradd --system --home-dir /opt/traefik --user-group --shell /usr/sbin/nologin traefik chown -R traefik:traefik /opt/traefik chmod -R g+w /opt/traefik
Création du service Systemd
vim /etc/systemd/system/traefik.service
[Unit]
Description=Traefik, circulez y'a rien à voir !
[Service]
RestartSec=2s
Type=simple
User=traefik
Group=traefik
WorkingDirectory=/opt/traefik
ExecStart=/opt/traefik/traefik --configFile=/opt/traefik/config/traefik.toml
Restart=always
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE
[Install]
WantedBy=multi-user.target
Chargement du service au démarrage du système
systemctl daemon-reload systemctl enable traefik.service systemctl start traefik.service systemctl status traefik.service
Configuration de base
Le fichier de configuration de Traefik est au format TOML, mais peux être également au format JSON. Il y a donc deux noms de fichier recommandés suivant le langage utilisé :
traefik.toml
traefik.yml
Ce fichier est attendu dans l'une de ces arborescences :
/etc/traefik/
$HOME/.config
.
(Dans la même arborescence que le binaire)
Nous pouvons également définir à Traefik un fichier de configuration spécifique :
traefik --configFile=foo/bar/myconfigfile.toml
ATTENTION
Dans ce fichier, il est attendu une configuration statique. Une modification de celui-ci nécessitera une relance de Traefik pour qu'elles soient prisent en compte. Sont également concernés les fichiers étrangers aux différents hôtes virtuels comme par exemple middleware.toml et tls.toml que nous verrons plus bas. Seules les fichiers contenants les directives routers et services ne nécessites pas de redémarrage du service.Voici un exemple:
vim /opt/traefik/config/traefik.toml
# Configuration globale de Traefik
[global]
sendAnonymousUsage = false # Évite l'envoi d'informations à l'éditeur
# Configuration des journaux de Traefik
[log]
level = "DEBUG" # Niveau de journalisation [DEBUG|PANIC|FATAL|ERROR|WARN|INFO]
format = "common" # Format des journaux [common|json]
filePath = "/opt/traefik/logs/traefik.log" # Chemin d'accès au fichier de journalisation
# Configuration des journaux d'accès
[accessLog]
filePath = "/opt/traefik/logs/access.log" # Chemin d'accès au fichier de journalisation
# Configuration des fourniseurs
[providers]
[providers.file] # Fournisseur de type "fichier"
directory = "/opt/traefik/config/vhosts/" # Chemin d'accès du répertoire où sont stockés les fichiers des services
watch = true # Permet le chargement à chaud des modifications de fichiers de configuration des hôtes virtuels
# Configuration de l'API
[api]
dashboard = true # Permet d'activer le tableau de bord de Traefik
debug = false # Permet de désactiver le mode développeur de l'API
insecure = true # Permet d'activer l'accès à l'API via le port 8080 par défaut
# Configuration des points d'entrées de Traefik
[entryPoints]
[entryPoints.http] # Permet de déclarer un point d'entrée nommé "http"
address = ":80" # Permet de déclarer le port d'entrée
ATTENTION
Pour lesfilePath
des sections [log]
et [accessLog]
, il faudra prévoir une rotation du fichier journal (voir Logrotate) car Traefik ne gère pas cette fonction. Ceci est indispensable pour ne pas voir votre partition se remplir jusqu'à déni de service.Comme nous avons édité le fichier de configuration principal du serveur, il faut recharger le service
systemctl restart traefik.service
Fonctionnalités
L'outil permet un éventail de fonctionnalités souvent rencontrées dans des logiciels de ce type. Elles sont décrites dans un ou plusieurs fichiers. Un hôte étant définit par des sections, il est possible d'en combiner plusieurs en un seul fichier ou d'en faire un par fichier. Ceci est configuré dans le paramètre directory
de la directive [providers]
vu précédemment. Comme précisé par le paramètre watch
de cette même directive, ces fichiers sont appliqués au serveur à chaque enregistrements.
Parmi les fonctionnalités que nous avons explorées, nous pouvons noter la possibilité de faire:
- un mandataire inverse HTTP/HTTPS
- l'ajout d'une authentification HTTP
- un répartiteur de charge
Afin de simplifier la compréhension des fichiers d'exemples qui suivront, nous allons partir du principe que nous voulons mettre à disposition de visiteurs sur Internet, un site WEB simple en HTML. Ce site est hébergé sur deux serveurs, ce qui nous permettra de configurer une répartition de charge. Nous le configurerons tout d'abord en HTTP, lui appliquerons une authentification, mettrons en place la répartition de charge et le passerons en HTTPS.
HTTP
Dans cette section, nous allons aborder la mise en place d'une redirection simple en HTTP comme on le ferrai avec Haproxy.
Nous allons créer un fichier représentant le nom du service:
vim /opt/traefik/config/vhosts/ma_page.toml
# Service de type http
[http]
[http.routers] # Déclaration des routers
[http.routers.vers_ma_page] # Création d'un routeur nommé "vers_ma_page"
rule = "Host(`mapage.jmador.yo`)" # URL avec laquelle sera joint notre site web
service = "ma_page" # Nom du service (déclaré ci-dessous)
[http.services] # Déclaration des services
[http.services.ma_page.loadBalancer] # Création d'un service nommé "ma_page"
[[http.services.ma_page.loadBalancer.servers]] # Déclaration d'un serveur
url = "http://[2001:db8:0:180::a0]" # URL vers mon serveur MaPage
Vous pouvez noter le mot clé loadBalancer
à la ligne créant le service ([http.services.ma_page.loadBalancer]
). En fait, Traefik fait constament de la répartition de charge, même avec un seul hôte (ce qui revient à toujours envoyer les requêtes sur la même machine). La configuration d'une réelle répartition de charge consiste donc à ajouter un hôte, d'où la simplicité de mise en œuvre. Nous verrons ceci plus bas.
Il est également possible de faire des règles (paramètre rule
) avec plus de conditions en utilisant des structures conditionnelles telles que ||
ou &&
.
Authentification
Pour l’authentification, nous avons besoin d'un "middlewares" qui intercepte le lien pour demander un utilisateur et un mot de passe :
Pour ce faire, nous allons créer un fichier htpasswd (utilitaire présent dans le paquet apache2-utils
):
htpasswd -c /opt/traefik/passwd/groupe1 ycharbi
ATTENTION
Si vous voulez ajouter un utilisateur, utilisez la commande suivante :htpasswd /opt/traefik/passwd/groupe1 nmorin
. L'usage du paramètre -c
ne devant être utilisé que pour la création du fichier, sous peine de l'écraser. De plus, il faut impérativement relancer le service pour prendre en compte tout ajout/modification/suppression.Un middleware est unique au sein de Traefik, bien qu'il soit possible de mettre la section dédiée directement dans l'hôte concerné, il est plus judicieux de leur créer un fichier propre afin de pouvoir piocher dedans les groupes d'utilisateurs pour les authentifications:
vim /opt/traefik/config/vhosts/middlewares.toml
# Service de type http
[http]
[http.middlewares] # Déclaration des middlewares
[http.middlewares.mon_auth.basicAuth] # Création d'un middleware nommé "mon_auth" de type "basicAuth"
usersFile = "/opt/traefik/passwd/groupe1" # Définit l'arborescence du fichier htpasswd
Puis nous allons reprendre le fichier /opt/traefik/config/vhosts/ma_page.toml
:
[http]
[http.routers]
[http.routers.vers_ma_page]
rule = "Host(`mapage.jmador.yo`)"
service = "ma_page"
middlewares = ["mon_auth"] # Définit les middlewares utilisés pour ce routeur
[http.services]
[http.services.ma_page.loadBalancer]
[[http.services.ma_page.loadBalancer.servers]]
url = "http://[2001:db8:0:180::a0]"
Répartition de charges
Nous allons voir la configuration de la répartition de charge. Plusieurs serveurs pourront êtres utilisés pour répondre de façon alternés aux clients. Attention, nous n'aborderons pas ici la notion de gestion de faillite (failover). Un serveur injoignable sera quand même utilisé dans la répartition et renvéra des erreurs aux clients.
L'ajout d'un serveur dans le système de répartition de charge est très simple. Il faut seulement déclarer un autre serveur dans le service. La répartition de charge utilise l'algorithme d'ordonnancement Round-robin.
Reprenons notre fichier /opt/traefik/config/vhosts/ma_page.toml
:
[http]
[http.routers]
[http.routers.vers_ma_page]
rule = "Host(`mapage.jmador.yo`)"
service = "ma_page"
middlewares = ["mon_auth"]
[http.services]
[http.services.ma_page.loadBalancer]
[[http.services.ma_page.loadBalancer.servers]]
url = "http://[2001:db8:0:180::a0]"
[[http.services.ma_page.loadBalancer.servers]] # Déclaration d'un autre serveur
url = "http://[2001:db8:0:180::a1]" # URL vers mon serveur 2 MaPage
Avec persistance de sessions
Traefik nous offre la possibilité de gérer la persistance de sessions sur un serveur de manière très simple. Il faut simplement ajouter la valeur .sticky.cookie
lors de la déclaration de notre service.
INFORMATION
La persistance de sessions permet d'allouer un client au premier serveur que le Round-robin lui aura fait joindre. La technique s'appuie sur la génération et l'envoi d'un cookie au navigateur du client (cela ne fonctionne donc pas avec curl ou wget). Celui-ci présente ce cookie au serveur mandataire qui retransmet sa requête au même serveur qu'au premier échange.Toujours dans notre fichier /opt/traefik/config/vhosts/ma_page.toml
:
# Service de type http
[http]
[http.routers]
[http.routers.vers_ma_page]
rule = "Host(`mapage.jmador.yo`)"
service = "ma_page"
middlewares = ["mon_auth"]
[http.services]
[http.services.ma_page.loadBalancer.sticky.cookie] # Création d'un service nommé "ma_page" avec gestion des cookies de session
[[http.services.ma_page.loadBalancer.servers]]
url = "http://[2001:db8:0:180::a0]"
[[http.services.ma_page.loadBalancer.servers]]
url = "http://[2001:db8:0:180::a1]"
HTTPS
Dans cette section nous ajouterons le support de TLS pour faire du HTTPS. Vous trouverez la documenation officielle sur le sujet ici ainsi que l'ensemble des suites cryptographiques configurables pour le chiffrement du flux et les algorithmes d'échange de clés basés sur les courbes ellyptiques (la syntaxes des algorithmes de la RFC 8446 est utilisable dans la configuration).
Simple
Le support de HTTPS se ferra en cohabitation avec HTTP. Les clients pourrons se connecter soit en clair, soit en chiffré.
Comme vous pouvez le voir dans le schéma ci-dessus, nous avons un nouveau point d'entrée sur le port 443. Il faut donc l'ajouter dans la configuration de base de Traefik.
vim /opt/traefik/config/traefik.toml
[global]
sendAnonymousUsage = false
# Configuration des journaux de Traefik
[log]
level = "DEBUG"
format = "common"
filePath = "/opt/traefik/logs/traefik.log"
[accessLog]
filePath = "/opt/traefik/logs/access.log"
[providers]
[providers.file]
directory = "/opt/traefik/config/vhosts/"
watch = true
[api]
dashboard = true
debug = false
insecure = true
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.https] # Permet de déclarer un autre point d'entrée nommé "https"
address = ":443" # Permet de déclarer le port d'entrée 443
Nous allons ajouter un nouveau fichier pour définir les propriétés pas défaut de notre TLS:
vim /opt/traefik/config/vhosts/tls.toml
[tls.options]
[tls.options.default]
# Définition des suites cryptographiques accéptés par le serveur
cipherSuites = [
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
]
curvePreferences = ["x25519", "CurveP521", "CurveP384"] # Définition des algorithmes d'échanges de clés accéptés par le serveur
preferServerCipherSuites = true # Imposer l'utilisation des suites cryptographiques définies par le serveur
Note: Il est à précisé que GoLang ne permet pas de configurer de suites cryptographiques pour le TLS 1.3. Les développeurs du langage se justifient par le fait qu'elles sont définits dans la RFC 8446, respectés à la lettres et concidérées comme sûr donc y'a pas de problèmes... Personellement je trouve ça moyen surtout quand l'AES 128 bits est le choix par défaut... Ce n'est peut-être que temporaire, l'ajout de ce protocole datant de la version 1.12 du langage Go (on en est à la 1.13 au moment de la rédaction de ce paragraphe).
ATTENTION
N'oubliez pas que comme nous avons modifié le fichier de configuration principal ainsi qu'un fichier autre qu'un routeur ou un service, il faut relancer Traefik pour que la prise en compte de la configuration soit effective.Dans le fichier /opt/traefik/config/vhosts/ma_page.toml
:
[http]
[http.routers]
[http.routers.vers_ma_page]
entryPoints = ["https"] # On force l'accès via le point d'entrée "https"
rule = "Host(`mapage.jmador.yo`)"
service = "ma_page"
middlewares = ["mon_auth"]
[http.routers.vers_ma_page.tls] # On autorise les connexion "TLS"
[http.services]
[http.services.ma_page.loadBalancer.sticky.cookie]
[[http.services.ma_page.loadBalancer.servers]]
url = "http://[2001:db8:0:180::a0]"
[[http.services.ma_page.loadBalancer.servers]]
url = "http://[2001:db8:0:180::a1]"
[[tls.certificates]]
certFile = "/opt/traefik/tls/mapage.jmador.yo/mapage.jmador.yo.crt" # Chemin d'accès au certificat
keyFile = "/opt/traefik/tls/mapage.jmador.yo/mapage.jmador.yo.key" # Chemin d'accès à la clé du certificat
Note: la génération des certificats est expliquée dans la documentation concernant OpenSSL. Prenez garde aux permissions de vos certificats. L'utilisateur "traefik" doit en être le propriétaire.
Avec redirection de HTTP vers HTTPS
Le support d'HTTPS sera obligatoire, toute connexion en HTTP redirigera automatiquement le client en HTTPS.
Comme nous pouvons le voir sur le schéma ci-dessus, il faut que l'on déclare un nouveau middlewares.
Reprenons notre fichier /opt/traefik/config/vhosts/middlewares.toml
:
[http]
[http.middlewares]
[http.middlewares.mon_auth.basicAuth]
usersFile = "/opt/traefik/passwd/groupe1"
[http.middlewares.redirection_https.redirectScheme] # Création d'un middleware nommé "redirection_https" de type "redirectScheme"
scheme = "https" # Redirection vers https
permanent = true # Permet l'envoie d'un code HTTP 301
Puis, dans notre fichier d'hôte /opt/traefik/config/vhosts/ma_page.toml
:
[http]
[http.routers]
[http.routers.vers_ma_page_http] # Création d'un routeur nommé "vers_ma_page_http"
entryPoints = ["http"] # On force l'accès via le point d'entrée "http"
rule = "Host(`mapage.jmador.yo`)" # URL avec laquelle sera joint notre site web
service = "ma_page" # Nom du service (même si on y va pas)
middlewares = ["redirection_https"] # Définit les middlewares utilisés pour ce routeur
[http.routers.vers_ma_page_https] # Création d'un routeur nommé "vers_ma_page_https"
entryPoints = ["https"]
rule = "Host(`mapage.jmador.yo`)"
service = "ma_page"
middlewares = ["mon_auth"]
[http.routers.vers_ma_page_https.tls]
[http.services]
[http.services.ma_page.loadBalancer.sticky.cookie]
[[http.services.ma_page.loadBalancer.servers]]
url = "http://[2001:db8:0:180::a0]"
[[http.services.ma_page.loadBalancer.servers]]
url = "http://[2001:db8:0:180::a1]"
[[tls.certificates]]
certFile = "/opt/traefik/tls/mapage.jmador.yo/mapage.jmador.yo.crt"
keyFile = "/opt/traefik/tls/mapage.jmador.yo/mapage.jmador.yo.key"
Supervision
Traefik permet d'exporter ses métriques au format OpenMetrics afin d'être exploités par des outils de supervision tel que Prometheus.
Pour cela il faut ajouter les paramètres suivants à la fin du fichier /opt/traefik/config/traefik.toml
:
[metrics]
[metrics.prometheus]
ATTENTION
Relancer Traefik pour la prise en compte de la configuration.