RousselTMLEARNING

TP · HAProxy : de la découverte à l'expertise

HAProxy et Docker : construire un cluster load balancé de haute disponibilité avec correction

La correction est intégrée au TP (Voir les encadrés de couleur vert)

Ce que vous allez apprendre dans ce TP
  • Lancer l'infrastructure multi-conteneurs
  • Localiser et éditer le fichier principal
  • Démarrer une instance HAProxy 3.4 avec une configuration de base
  • Analyser les logs
  • Comprendre les sections de configuration
  • Comprendre l'importance de la modularité
  • Apprendre à gérer l'inclusion de dossiers de configuration
  • Comprendre l'importance de la différence entre reload et restart
  • Configurer un frontend dédié à l'administration
  • Tester l'accessibilité du tableau de bord de statistiques natif de HAProxy
  • Configurer le frontend principal pour le trafic HTTP
  • Configurer un backend par défaut
  • Comprendre la répartition de charge : Round Robin, Least connection, ...
  • Comprendre la notion de poids
  • Comprendre la notion de X-FORWARD-FOR
  • Comprendre la notion de HA
  • Manipuler les ACL
  • Configurer un check de niveau 7
  • Configurer la recherche de pattern dans la sortie du check
  • Limiter les connexions simultanées (Anti-DoS/DDoS)
  • Se protéger contre les attaques lentes (Slowloris)
  • Mettre en place un quota de requêtes (Rate Limiting)
  • Identifier et filtrer les automates (Anti-bot/Scraping)
  • Utiliser la terminaison silencieuse (Silent Drop) pour les flux interdits

Mise en place de l'infrastructure #

Ce que vous allez apprendre dans cette section
  • Lancer l'infrastructure multi-conteneurs
Déploiement de 3 serveurs web, d'un serveur Nginx et d'un cluster HAProxy via Docker Compose.



IMPORTANT : Vous devez lire cet article avant de commencer ce TP pour bien maîtriser les fondamentaux.

Nous vous recommandons aussi de suivre ces formations :
  • Docker : Pour mieux comprendre l'importance de la conteneurisation
  • Prometheus : Pour mieux comprendre la notion de métriques et leurs gestions
  • Opentelemetry : Pour mieux comprendre la notion de métriques et leurs gestions
  • Grafana : Pour mieux comprendre la visualisation des données de télémétrie
. Mais cela n'est pas indispensable, car nous fournirons pour ce TP toutes les commandes pour ces produits.
  1. Obtention des sources

    Vous devez cloner les sources du projet depuis ce dépôt (repository) https://github.com/rousseltm/haproxy-formation.git dans le dossier de votre choix.
    git clone https://github.com/rousseltm/haproxy-formation.git
  2. Mise en place de l'infrastructure

    Pour tester nos configurations, on aura besoin d'une infrastructure minimale. Vous devez lancer les commandes suivantes pour la déployer sur Docker :
    cd haproxy-formation 
    sudo docker compose -f compose-infra.yaml up -d
    Attention : Toutes les commandes docker compose devront être lancées dans le dossier haproxy-formation.

Prise en main de la configuration #

Ce que vous allez apprendre dans cette section
  • Localiser et éditer le fichier principal
  • Démarrer une instance HAProxy 3.4 avec une configuration de base
  • Analyser les logs
  • Comprendre les sections de configuration
  • Comprendre l'importance de la modularité
  • Apprendre à gérer l'inclusion de dossiers de configuration
  • Comprendre l'importance de la différence entre reload et restart

Exploration de la structure de configuration et mise en place de la modularité.

  1. Accéder au fichier de base haproxy.cfg

    Le cœur de HAProxy réside dans son fichier de configuration principal : haproxy.cfg. Dans notre environnement Docker, ce fichier est monté en volume.
    Le fichier se situe dans config/haproxy/haproxy.cfg. Vous pouvez l'ouvrir avec votre éditeur de texte habituel pour observer les sections déjà présentes.
  2. Démarrage de l'instance de base

    Pour tester nos configurations, on aura besoin d'une infrastructure HAProxy 3.4 avec une configuration de base que l'on va modifier par la suite. Dans un premier temps, on va tester son fonctionnement avec la configuration de base avec la commande suivante :
    sudo docker compose up -d
  3. Vérification du démarrage

    L’objectif est d’apprendre à identifier les erreurs de configuration à travers les logs système et Docker et de vérifier l’absence d’erreurs dans les logs générés par HAProxy.
    Installation sur machine virtuelle ou machine physique : Les logs sont généralement disponibles dans /var/log/haproxy.log ou via la commande
    journalctl -u haproxy
    Installation via Docker Compose (notre cas) : Utilisez la commande suivante pour consulter les logs de toutes les instances :
    sudo docker compose logs -f haproxy
    ou cette commande pour consulter ceux d'une instance en particulier (nom du conteneur 3 : haproxy-formation-haproxy-3)
     sudo docker logs <container_name>
    Avec la configuration fournie, vous pouvez rencontrer des erreurs comme :
    haproxy-1 | [ALERT] (1) : config : parsing [/usr/local/etc/haproxy/haproxy.cfg:71]: Missing LF on last line, file might have been truncated at position 32.
    Vous devez comprendre le message et le corriger.
    L'erreur vous informe simplement qu'il manque un saut de ligne à la fin du fichier (LF).
    BONNE PRATIQUE : Toujours tester vos configurations avant de relancer votre instance en production : option -c
  4. L'importance de la modularité

    À grande échelle, maintenir un fichier haproxy.cfg monolithique devient complexe et risqué. La modularité permet de séparer les responsabilités (ex. : un fichier par application, un pour le monitoring, un pour la sécurité, etc.), facilitant ainsi le déploiement continu, les revues de code et la limitation des erreurs humaines lors des mises à jour.

    Par défaut, le service HAProxy est lancé avec l'option -f haproxy.cfg. Vous pouvez ajouter autant d'options -f que vous avez de fichiers, mais vous pouvez aussi utiliser la même option et passer un dossier en paramètre : HAProxy chargera tous les fichiers se terminant par .cfg dans ce dossier.

    Attention à bien prendre en compte la dépendance entre les modules !


    Dans notre cas, avec notre configuration Docker Compose, utilisez la commande suivante pour basculer vers l'utilisation du dossier conf.d (pensez à déplacer le fichier de conf dans ce dossier), qui se trouve au même niveau que le fichier haproxy.cfg. Les blocs de configuration des exercices suivants devront donc être placés dans un fichier .cfg de ce dossier, par exemple config/haproxy/conf.d/tp.cfg :
    sudo docker compose down; export HAPROXY_CONFIG=conf.d; sudo -E docker compose up -d
  5. Rechargement de la configuration

    Chaque modification du fichier nécessite une prise en compte par le moteur HAProxy.
    Reload vs Restart : En production, n'utilisez jamais le restart car il coupe les connexions. Le Reload (signal HUP) permet de charger la nouvelle configuration sans aucune interruption de service.
    Vous devez trouver la commande pour recharger votre serveur sans couper les connexions en cours via systemctl et via Docker.
    Pour recharger avec systemctl :
    sudo systemctl reload haproxy
    Pour recharger proprement avec Docker Compose (Reload) :
    sudo docker compose kill -s HUP haproxy
    Pour un redémarrage complet (Restart) :
    sudo docker compose restart haproxy

    Pour en savoir plus, consultez l'article sur les bonnes pratiques de configuration.

Gestion des Frontends #

Ce que vous allez apprendre dans cette section
  • Configurer un frontend dédié à l'administration
  • Tester l'accessibilité du tableau de bord de statistiques natif de HAProxy
  • Configurer le frontend principal pour le trafic HTTP

Configuration des points d'entrée pour les statistiques et le trafic HTTP.

  1. Point d'entrée pour l'administration

    Créez un point d'entrée dédié au monitoring nommé 'admin'. Ce point d'entrée doit écouter sur le port 8404 (port par défaut). Vous devez activer l'interface de statistiques, définir la racine (/) comme URI d'accès et configurer un rafraîchissement automatique toutes les 5 secondes. Notez que vous pouvez réaliser cette configuration avec un bloc frontend ou un bloc listen, le résultat sera identique.
    Comme nous avons basculé vers le chargement du dossier conf.d, ajoutez cette configuration dans un fichier .cfg de ce dossier. Pour appliquer vos modifications, utilisez la commande export HAPROXY_CONFIG=conf.d; sudo -E docker compose restart haproxy (bien faire un reload en Production).
    Vous pouvez éditer le fichier de configuration HAProxy pour ajouter cette configuration :
    frontend admin
        bind :8404
        stats enable
        stats uri /
        stats refresh 5s
    Et ensuite, relancer le service.
  2. Test de l'accès aux statistiques

    Après avoir configuré le frontend 'admin', vérifiez que l'interface de monitoring est bien opérationnelle. Vous pouvez utiliser votre navigateur ou une commande terminal pour tester l'accessibilité du service sur le port dédié.

    Vérifiez l'accès en ouvrant l'URL suivante dans votre navigateur :

    http://localhost:8404

    Vous pouvez également valider la connectivité avec curl :

    curl http://localhost:8404
  3. Frontend HTTP

    Configurez le frontend principal nommé 'http_in' pour recevoir le trafic web des utilisateurs. Il doit écouter sur le port 80 et rediriger par défaut toutes les requêtes vers le groupe de serveurs 'default' (qui sera créé par la suite).

    frontend http_in
        bind :80
        default_backend default

Gestion des Backends #

Ce que vous allez apprendre dans cette section
  • Configurer un backend par défaut
  • Comprendre la répartition de charge : Round Robin, Least connection, ...
  • Comprendre la notion de poids
  • Comprendre la notion de X-FORWARD-FOR
  • Comprendre la notion de HA

Configuration des serveurs de destination pour traiter les requêtes.

  1. Le Backend par défaut

    Créez un groupe de serveurs nommé 'default'. Ce backend sera utilisé pour traiter les requêtes ne correspondant à aucune règle spécifique. Il doit fonctionner en mode HTTP, utiliser l'algorithme 'roundrobin' et pointer vers le serveur 'web1'. Configurez une règle pour que ce backend serve systématiquement le fichier 'default.html'.

    backend default
        mode http
        balance roundrobin
        # Réécriture du chemin pour afficher la page de maintenance
        http-request set-path /default.html
        # Déclaration des nœuds applicatifs
        server web1 web1:80 check
  2. Reload à chaud via fichier de conf

    Ouvrez votre interface de statistiques (port 8404). Vous devriez normalement voir 1 serveur actif dans le backend default. L'objectif est d'ajouter le serveur web2 à ce pool à chaud, c'est-à-dire sans redémarrer le conteneur HAProxy, afin de préserver les connexions en cours. Les étapes :
    • Voir la date de création des conteneurs HAProxy : L'information est dans la colonne 'CREATED'
      sudo docker compose ps haproxy
    • Vous devez éditer le fichier pour ajouter le second serveur et recharger le service :
      sudo docker compose kill -s HUP haproxy
    • Vous devez vérifier dans l'interface que le nouveau serveur est bien présent et que la date de création du conteneur n'a pas changé

    1. Ajoutez le serveur web2 dans le bloc backend default de votre fichier de configuration chargé par HAProxy:

    server web2 web2:80 check

    2. Pour recharger la configuration sans redémarrer le conteneur, envoyez un signal de rechargement (SIGHUP) au processus HAProxy :

    sudo docker compose kill -s HUP haproxy

    Vérifiez sur le dashboard de statistiques : le backend default doit maintenant afficher 2 serveurs sans que l'Uptime du service n'ait été réinitialisé.

  3. Reload à chaud via socat

    HAProxy dispose d'une Runtime API accessible via une socket Unix. Elle permet de modifier l'état du load balancer (poids, état des serveurs, ajout dynamique) sans aucun rechargement.
    Pour inspecter l'état interne ou passer des commandes directement dans votre conteneur, connectez-vous au shell via :
    sudo docker exec -it <nom_du_conteneur> sh

    Pour utiliser l'API, vous devez avoir activé la socket dans la section global de la configuration chargée par HAProxy :
    stats socket /tmp/admin.sock mode 600 level admin
    Recommandation de lecture : Pour approfondir la gestion dynamique des backends et des serveurs via la Runtime API, consultez notre article dédié : HAProxy : Ajout et suppression dynamique de backends.
    En ajoutant, vous devez voir le serveur apparaitre dans votre page de stats Mais comme vous avez peu le constater la commande socat est une commande locale donc il faut la jouter sur l'ensemble des instances de votre cluster HAProxy. De plus, comme indiqué dans la documentation, ajouter un serveur ne suffit pas pour qu'il reçoive le trafic, il faut l'activer ...

    1. Connectez-vous au conteneur HAProxy :

    docker exec -it <nom_du_conteneur> sh

    2. Utilisez socat pour envoyer la commande d'ajout au moteur :

    echo "add server default/web3 web3:80 check" | socat stdio /tmp/admin.sock

    3. Par défaut, un serveur ajouté dynamiquement est en mode maintenance. Activez-le :

    echo "enable server default/web3" | socat stdio /tmp/admin.sock

    4. Il faut aussi activer le healthcheck :

    echo "enable health default/web3" | socat stdio /tmp/admin.sock

    Vérifiez sur le dashboard : le serveur web3 apparaît instantanément. Mais attention à socat qui ne gère pas la persistence et a une exécution locale

  4. Le Backend web_servers

    Créez un groupe de serveurs nommé 'web_servers'. Ce backend doit fonctionner en mode HTTP et utiliser l'algorithme de répartition 'least connection' avec chaque backend qui a un poids qui correspond à son id de serveur. Vous devez également ajouter une règle pour transmettre l'adresse IP réelle du client au backend via l'en-tête 'X-Real-IP' et déclarer les 3 nœuds applicatifs (web1, web2, web3) sur le port 80 avec une vérification de santé (check). Enfin, mettez à jour le frontend http_in pour envoyer le trafic par défaut vers ce backend.
    frontend http_in
        bind :80
        default_backend web_servers
    
    backend web_servers
        mode http
        balance leastconn
        http-request set-header X-Real-IP %[src]
        # Déclaration des 3 nœuds applicatifs du cluster
        server web1 web1:80 weight 1 check
        server web2 web2:80 weight 2 check
        server web3 web3:80 weight 3 check
  5. Scaling de HAProxy

    Le passage à l'échelle horizontal (scaling) consiste à multiplier les instances de HAProxy pour garantir la haute disponibilité (HA). Dans une architecture réelle, avoir une seule instance de load balancer crée un 'Single Point of Failure' (SPOF) : si HAProxy tombe, toute l'application est inaccessible, même si les serveurs web sont sains. En environnement Docker, le scaling permet de répartir la charge réseau et d'assurer une continuité de service lors des mises à jour (rolling updates). Vous devez lancer la commande Docker Compose avec le paramètre --scale haproxy=3 pour faire passer le nombre d'instances HAProxy à 3.

    Note : Multiplier le nombre de nœuds HAProxy ne suffit pas à le mettre en haute disponibilité. Il faut qu'il dispose d'une VIP : dans notre cas, c'est Nginx qui fera le load balancing pour assurer une haute disponibilité complète.

    Pour passer votre point d'entrée à l'échelle dans le monde Docker sans modifier votre fichier de configuration compose.yml, nous utilisons le paramètre d'exécution --scale :

    Déploiement : Appliquez la nouvelle topologie :

    sudo -E docker compose up -d --scale haproxy=3

    Pourquoi est-ce important ?

    • Résilience : Si un conteneur HAProxy plante, les autres instances continuent de répondre.
    • Maintenance à chaud : Vous pouvez redémarrer ou mettre à jour une instance sans interrompre le trafic global.
    • Performance : En production, ces instances seraient réparties sur différents nœuds physiques (via Docker Swarm ou Kubernetes), ce qui permettrait d'absorber des débits réseau massifs.
    Note : En local avec Docker Compose, les instances peuvent partager le même mappage de port si vous utilisez un réseau de type 'overlay' ou un load balancer amont.
  6. Synchronisation des sessions avec le 'Peering'

    Dans un cluster HAProxy haute disponibilité, un basculement entre deux nœuds peut provoquer la perte des informations de persistance si chaque instance conserve ses données localement. Pour éviter ce problème, HAProxy intègre un mécanisme natif appelé Peers qui permet de répliquer en temps réel le contenu des Stick Tables entre plusieurs serveurs HAProxy. Cette fonctionnalité garantit que les informations de session, les compteurs de limitation de débit (Rate Limiting), les détections d'abus ou encore les données d'affinité client restent cohérentes après un failover.

    IMPORTANT : Le peering ne synchronise pas les sessions applicatives (PHP, Java, .NET, etc.). Il réplique uniquement les données stockées dans les Stick Tables HAProxy. Pour partager les sessions applicatives, il est recommandé d'utiliser une solution externe comme Redis ou Memcached.


    Que peut-on synchroniser avec les Peers ?
    • Persistance de session : maintien de l'affinité entre un client et son serveur backend.
    • Rate Limiting : partage des compteurs de requêtes entre les nœuds HAProxy.
    • Protection contre les abus : détection distribuée des attaques ou comportements suspects.
    • Tracking utilisateur : conservation d'informations liées aux clients même après un basculement.

    Les Peers sont particulièrement utiles dans les architectures utilisant Keepalived ou VRRP où une adresse IP virtuelle peut migrer d'un HAProxy à un autre.

    Bonnes pratiques :
    • Utilisez un réseau dédié ou isolé pour les échanges de peering afin d'éviter les interférences avec le trafic utilisateur.
    • Vérifiez que les ports utilisés pour les Peers sont accessibles entre les nœuds du cluster.
    • Conservez une définition identique de la section peers sur l'ensemble des serveurs HAProxy.
    • Surveillez l'état de synchronisation via la Runtime API ou la page de statistiques HAProxy.
    • Pour les applications stateful, privilégiez malgré tout une externalisation des sessions dans Redis afin d'éviter toute dépendance au load balancer.
    Vous devez ajouter une section pour le partage des sessions nommée 'haproxy_cluster' et qui utilise les trois serveurs HAProxy haproxy-formation-haproxy-1/2/3 sur le port par défaut. Vous devez donc activer ce partage de session dans le backend 'web_servers' pour une taille de 100k pour une expiration après 30m et se basant sur l'IP source du visiteur.

    Chaque membre du cluster doit déclarer la même section peers avec la liste complète des nœuds participant à la réplication. Ensuite, les Stick Tables doivent être associées à ce groupe de Peers afin que leur contenu soit automatiquement synchronisé.

    peers haproxy_cluster
        peer haproxy1 haproxy-formation-haproxy-1:1024
        peer haproxy2 haproxy-formation-haproxy-2:1024
        peer haproxy3 haproxy-formation-haproxy-3:1024
    
    backend web_servers
        # Table synchronisée entre tous les HAProxy
        stick-table type ip size 100k expire 30m peers haproxy_cluster
    
        # Affinité basée sur l'adresse IP source
        stick on src
    
        # L'ancienne configuration
        mode http
        balance leastconn
        http-request set-header X-Real-IP %[src]
        server web1 web1:80 weight 1 check
        server web2 web2:80 weight 2 check
        server web3 web3:80 weight 3 check

Routage avancé avec ACL #

Ce que vous allez apprendre dans cette section
  • Manipuler les ACL
  • Configurer un check de niveau 7
  • Configurer la recherche de pattern dans la sortie du check

Rediriger les requêtes commençant par /api vers le serveur 2.

  1. Modification ACL

    Le routage intelligent permet de diriger le trafic vers différents backends selon des critères précis. Dans cet exercice, vous devez reconfigurer HAProxy pour qu'il identifie les requêtes destinées à l'API (commençant par le chemin /api) et les envoie exclusivement vers le backend secure_servers qui contient les serveurs du service web mais uniquement de la 2e à la 10e occurrence. Le trafic restant doit continuer à être distribué par le backend par défaut.

    Par défaut, HAProxy va faire des tests de niveau 4 (TCP - IP:PORT) mais vous devez modifier le backend pour faire un test de vie de niveau 7 (HTTP - page web) qui vérifie que la page 'secure.html' retourne bien la chaîne 'Service\ '
    Voici un exemple de configuration (il est conseillé de le dispatcher en plusieurs fichiers) avec un bloc pour le frontend, la résolution des services docker et un pour le backend
    frontend http_in
        bind *:80
        # On définit une ACL qui vérifie si le chemin commence par /api
        acl is_api path_beg /api
        # On demande à HAProxy d'utiliser un backend spécifique si l'ACL est vraie
        use_backend secure_servers if is_api
        default_backend web_servers
    
    resolvers docker
        # DNS interne Docker (permet resolution des noms de containers)
        nameserver dns 127.0.0.11:53
        # Nombre de tentatives en cas d'echec DNS
       resolve_retries 3
        # Timeout global pour une requete DNS
       timeout resolve 1s
        # Temps d'attente entre deux tentatives de resolution
        timeout retry 1s
        # Duree pendant laquelle une resolution est consideree valide
        # Important pour eviter les re-resolutions trop frequentes
        hold valid 10s
    
    backend secure_servers
        # Healthcheck HTTP personnalise
        option httpchk GET /secure.html
        # Verifie que la reponse contient bien 'Service'
        http-check expect string Service\ 
        # Pool dynamique securise
        server-template web 2-10 web:80 check resolvers docker init-addr libc,none
  2. Whitelisting des IP

    Le filtrage par adresse IP est un pilier de la sécurité. Vous devez maintenant restreindre l'accès au dashboard de statistiques (port 8404) pour n'autoriser que les sources internes qui ont besoin : dans notre cas le serveur prometheus (dns prometheus dans docker) et les administrateurs.

    Whitelisting vs Blacklisting :

    HAProxy est compatible avec les deux approches via ses règles d'ACL.

    • Whitelisting (liste blanche) : Stratégie 'Default Deny'. On bloque tout par défaut et on n'autorise que les sources connues. C'est l'approche la plus robuste pour la sécurité.
      Cas d'usage : accès à une console d'administration, API interne réservée à des partenaires, restriction d'accès aux IP d'un VPN d'entreprise.
    • Blacklisting (liste noire) : Stratégie 'Default Allow'. On laisse passer tout le trafic sauf les IP identifiées comme malveillantes.
      Cas d'usage : blocage de bots connus (scrapers), protection temporaire contre une IP réalisant une attaque par force brute, ou Geo-blocking (blocage de régions entières).

    En environnement réel, n'oubliez pas d'ajouter les IP de vos passerelles VPN ou de vos bureaux. Dans notre infrastructure de TP, les services internes Docker utilisent le sous-réseau du projet ; on l'autorise donc pour conserver l'accès depuis Prometheus et Nginx d'administration. Voici comment appliquer ce filtrage sur le frontend des statistiques :

    frontend admin
        bind :8404
        # Définition de l'ACL basée sur l'IP source (src)
        acl allowed_monitors src nginx-admin prometheus
        # On refuse l'accès si l'IP n'est pas autorisée
        http-request deny if !network_allowed
    
        stats enable
        stats uri /
        stats refresh 5s
    Astuce de factorisation : Si vous avez une liste d'IP que vous souhaitez réutiliser dans plusieurs frontends, évitez de les copier-coller. Utilisez un fichier externe (ex. : /etc/haproxy/whitelist.lst) contenant une IP ou un CIDR par ligne. Votre ACL devient alors simple et centralisée :
    acl network_allowed src -f /etc/haproxy/whitelist.lst

Sécurité et Durcissement #

Ce que vous allez apprendre dans cette section
  • Limiter les connexions simultanées (Anti-DoS/DDoS)
  • Se protéger contre les attaques lentes (Slowloris)
  • Mettre en place un quota de requêtes (Rate Limiting)
  • Identifier et filtrer les automates (Anti-bot/Scraping)
  • Utiliser la terminaison silencieuse (Silent Drop) pour les flux interdits

Protection du cluster contre les abus et les attaques réseau.

  1. Protection contre le DoS et le DDoS

    Configurez le frontend http_in pour limiter chaque IP source à un maximum de 15 connexions TCP simultanées (couche 4). Une fois la configuration appliquée, tentez d'ouvrir plusieurs connexions en parallèle pour vérifier que HAProxy rejette les suivantes.
    Vérification : Simulez une charge avec une boucle shell pour ouvrir de nombreuses connexions en arrière-plan :
    for i in $(seq 1 20); do curl -s http://localhost & done
    Regardez vos logs HAProxy ou le dashboard : les connexions au-delà de 15 doivent être rejetées immédiatement.
    DoS vs DDoS : quelle différence ?
    • DoS (Denial of Service) : l'attaque provient d'une seule machine. HAProxy peut facilement la bloquer en limitant les connexions par IP.
    • DDoS (Distributed DoS) : l'attaque provient de milliers de sources (botnet). Bloquer une IP ne suffit plus, car le trafic est distribué.
    Recommandations de HAProxy (Lire l'article officiel) :
    • Défense en profondeur : pour les attaques volumétriques massives (couches 3 et 4), utilisez des services de protection Cloud (Cloudflare, AWS Shield) en amont.
    • Filtrage couche 7 : utilisez HAProxy pour identifier des signatures d'attaque spécifiques dans les en-têtes ou les URL via les ACL.
    • Stick Tables : elles restent essentielles pour limiter l'impact de chaque nœud du botnet sur vos ressources applicatives.

    Mode opératoire :

    1. Modifiez le frontend http_in existant pour intégrer le suivi des connexions :
    frontend http_in
        bind :80
        # Création de la table de suivi
        stick-table type ip size 100k expire 30s store conn_cur
        # Suivi de l'IP source
        tcp-request connection track-sc0 src
        # Rejet au-delà de 15 connexions
        tcp-request connection reject if { sc0_conn_cur gt 15 }
        default_backend web_servers

    2. Rechargez HAProxy.

  2. Protection contre le Slowloris

    L'attaque Slowloris sature le serveur en envoyant des en-têtes HTTP très lentement. Implémentez une protection en limitant le temps de réception des en-têtes à 5 secondes.
    Simulation d'attaque : Lancez cette commande avant la configuration (la connexion restera bloquée), puis après (HAProxy coupera la connexion après 5 s) :
    curl -X GET "http://localhost:80/" \
         -H "X-Slow: $(head -c 5000 < /dev/zero | tr '\0' 'A')" \
         --limit-rate 1 \
         --verbose
    Explication des paramètres :
    • -H "X-Slow: ..." : génère un en-tête massif de 5000 octets (via head et tr) pour forcer un envoi long.
    • --limit-rate 1 : bride l'envoi à 1 octet/s. Sans protection, la connexion resterait ouverte plus d'une heure.
    • --verbose : permet d'observer en direct le moment exact où HAProxy interrompt la session.
    Recommandations de HAProxy (Lire l'article officiel) : Pour une protection optimale, HAProxy préconise de combiner plusieurs réglages :
    • timeout http-request 5s : limite le temps d'attente des en-têtes (défense principale).
    • timeout http-keep-alive 1s : libère rapidement les slots de connexion inactifs.
    • maxconn : limite le nombre global de connexions pour protéger les descripteurs de fichiers du système contre l'épuisement.

    Mode opératoire :

    1. Dans la section defaults (ou le frontend), ajoutez la directive de timeout :
    defaults
        # Coupe la connexion si les en-têtes mettent plus de 5 s à arriver 
        timeout http-request 5s
        # 
        timeout http-keep-alive 1s
        #
        maxconn 10000

    2. Rechargez HAProxy et relancez la commande de simulation. Vous devriez voir un message Empty reply from server ou une fermeture de socket après environ 5 secondes.

  3. Limiter les requêtes (Rate Limiting)

    Mettez en place un quota de 50 requêtes maximum toutes les 10 secondes par IP. Testez le dépassement du seuil et vérifiez que HAProxy retourne bien un code d'erreur HTTP 429.
    Vérification : Exécutez une rafale de requêtes curl pour saturer le quota :
    for i in $(seq 1 60); do curl -I http://localhost; done
    Vous devez observer des réponses HTTP/1.1 429 Too Many Requests après la 50e requête.

    Mode opératoire :

    1. Mettez à jour la stick-table du frontend http_in pour suivre à la fois les connexions en cours et le débit de requêtes (http_req_rate) :
    frontend http_in
        bind :80
        # On conserve conn_cur et on ajoute le stockage du débit sur 10s
        stick-table type ip size 100k expire 30s store conn_cur,http_req_rate(10s)
        tcp-request connection track-sc0 src
        tcp-request connection reject if { sc0_conn_cur gt 15 }
        # Suivi au niveau HTTP (sc1)
        http-request track-sc1 src
        # Blocage avec code 429 (Too Many Requests)
        http-request deny deny_status 429 if { sc1_http_req_rate gt 50 }
        default_backend web_servers

    2. Rechargez la configuration.

  4. Modules Anti-bot et Détection du scraping

    Bloquez les aspirateurs de données (scrapers) et les bots malveillants en identifiant leurs signatures User-Agent suspectes.
    Simulation de bot : Tentez d'accéder au site en simulant un bot connu via curl :
    curl -I -H "User-Agent: Googlebot-Scraper" http://localhost/

    Mode opératoire :

    1. Ajoutez ces ACL et cette règle dans le frontend http_in existant, en conservant les protections déjà configurées :
        # Détection de mots-clés dans le User-Agent (insensible à la casse)
        acl is_bot hdr_sub(user-agent) -i bot crawler scraper spider
        # Rejet des requêtes identifiées comme bots
        http-request deny deny_status 403 if is_bot

    2. Rechargez HAProxy et vérifiez que votre requête curl avec l'en-tête suspect est désormais rejetée par un code 403.

  5. Terminaison silencieuse de requête

    Le 'Silent Drop' est une technique de défense avancée : au lieu d'envoyer un code d'erreur (403/429) qui confirme au pirate l'existence d'une protection, HAProxy ignore simplement la requête. L'attaquant gaspille ses ressources à attendre une réponse qui ne viendra jamais.
    Vérification : Testez l'accès à un chemin interdit et constatez que curl reste en attente (hang) jusqu'au timeout :
    curl -v http://localhost/admin/config

    Mode opératoire :

    1. Ajoutez l'action silent-drop dans le frontend http_in existant pour les chemins ou flux interdits :
        acl is_forbidden path_beg /admin
        # Fermeture de la connexion sans envoyer le moindre bit de réponse
        http-request silent-drop if is_forbidden

    2. Rechargez la configuration. Le client ne recevra aucune donnée (pas même un TCP RST), ce qui est particulièrement efficace contre les scanners automatiques.

Observabilité #

Mise en place du monitoring, de l'exposition des métriques et de la télémétrie.

  1. Stats Dashboard

    Vérifiez que le point d'entrée d'administration configuré plus tôt expose toujours le dashboard de statistiques sur la racine du port 8404.

    frontend admin
        bind :8404
        stats enable
        stats uri /
        stats refresh 5s
  2. Prometheus : Exposition des métriques

    Configurez HAProxy pour exposer les métriques de performance au format Prometheus sur l'URI /metrics. Cela permet à un serveur Prometheus de scraper l'état du load balancer.
    Vérification : Testez la récupération des métriques via curl :
    curl http://localhost:8404/metrics
    Vous devriez voir défiler les métriques au format texte brut (HELP et TYPE).

    Mode opératoire :

    1. Dans votre bloc frontend admin, utilisez la directive http-request use-service :
    frontend admin
        bind :8404
        stats enable
        stats uri /
        stats refresh 5s
        # Exposition des métriques pour Prometheus
        # Cette règle intercepte les requêtes sur l'URI '/metrics' et renvoie le format Prometheus
        http-request use-service prometheus-exporter if { path /metrics }

    2. Rechargez la configuration. HAProxy sert désormais les métriques sur le même port que le dashboard.

  3. Prise en charge d'OpenTelemetry (OTel)

    Configurez l'exportation native de données de télémétrie vers un collecteur OpenTelemetry.
    Note : La prise en charge native d'OpenTelemetry est disponible à partir de la version 3.4 de HAProxy.

    Mode opératoire :

    1. Déclarez l'exportateur OTel dans la section global :
    global
        otel-exporter my-collector
            endpoint otel-collector:4317

    2. Activez l'envoi des traces dans votre frontend pour propager le contexte :

    frontend http_in
        http-request otel-send-trace

Niveau de difficulté : ●●●○○ (3/5)

Glossaire de la formation

ACL (Access Control List)

Liste de contrôle d'accès définissant les permissions accordées sur des ressources. Dans HAProxy, les ACL sont des conditions flexibles permettant de ...

Backend

Section de la configuration HAProxy définissant un pool de serveurs cibles vers lesquels le trafic est redirigé. C'est ici que l'on configure l'algori...

Frontend

Section de la configuration HAProxy qui définit comment les requêtes sont reçues du côté client (adresse IP, port, certificats SSL) avant d'être envoy...

GSLB (Global Server Load Balancing)

Technique de répartition de charge à l'échelle mondiale, utilisant généralement le DNS pour diriger les utilisateurs vers le datacenter le plus proche...

HAProxy

Logiciel de load balancing et de proxying haute performance pour TCP et HTTP. HAProxy est le standard de l'industrie pour la gestion de trafic à très ...

Health Check

Mécanisme automatisé permettant au load balancer de tester périodiquement la disponibilité des serveurs afin d'exclure temporairement ceux qui sont en...

Load Balancing

Dispositif qui distribue le trafic applicatif sur un ensemble de serveurs afin d'optimiser l'usage des ressources, de minimiser les temps de réponse e...

SSL Offloading

Processus consistant à déléguer le déchiffrement du trafic HTTPS au load balancer pour libérer de la puissance CPU sur les serveurs d'application.

Stickiness

Mécanisme garantissant qu'un utilisateur est systématiquement redirigé vers le même serveur backend durant toute sa session, indispensable pour les ap...

Slowloris

Type d'attaque par déni de service (DoS) qui consiste à ouvrir de nombreuses connexions HTTP et à les maintenir ouvertes le plus longtemps possible en...

DoS / DDoS

Attaque visant à rendre un service indisponible en submergeant le serveur ou le réseau de trafic. On parle de DDoS (Distributed Denial of Service) lor...

SSL / TLS

Protocoles de sécurisation des échanges sur internet. TLS (Transport Layer Security) est le successeur moderne de SSL (Secure Sockets Layer). Ils perm...

Articles recommandés

Visualiser votre infrastructure avec HAProxy Topology Visualizer

Apprenez à utiliser HAProxy Topology Visualizer pour transformer vos fichiers haproxy.cfg complex...

HAProxy dans Kubernetes : L'Ingress Controller Haute Performance

Découvrez en profondeur l'intégration de HAProxy dans Kubernetes. Architecture Direct-to-Pod, opt...

Gestion des certificats SSL/TLS avec Let's Encrypt et ACME

Apprenez à automatiser la génération et le renouvellement de vos certificats SSL/TLS avec Let's E...

Maîtriser les ACLs dans HAProxy : Le Guide Complet

Guide complet sur les ACLs HAProxy : apprenez à configurer le routage intelligent, le contrôle d'...

HAProxy comme Ingress Controller Kubernetes : Le Guide de Production

Découvrez comment utiliser HAProxy comme Ingress Controller dans Kubernetes. Architecture Direct-...

Nouveautés HAProxy : OpenTelemetry, JWT Natif, et Optimisations de Performance

Explorez les dernières innovations de HAProxy : prise en charge native d'OpenTelemetry pour l'obs...

Le Load Balancing : Principes, Algorithmes et Cas d'usage

Découvrez le fonctionnement de la répartition de charge (Load Balancing), son rôle dans la haute ...

Anatomie de la configuration HAProxy, Clustering et Haute Disponibilité

Comprendre la structure d'un fichier haproxy.cfg : sections Global, Defaults, Frontend, Backend e...

Maîtriser les ACLs dans HAProxy

Guide complet sur les ACLs HAProxy : apprenez à configurer le routage intelligent, le contrôle d'...

Sécurité et SSL avec HAProxy

Guide complet sur la terminaison SSL, le chiffrement des flux et la sécurisation du serveur HAProxy.

Monitoring et Statistiques dans HAProxy

Comment activer le tableau de bord de statistiques natif et exposer des métriques pour Prometheus.

Persistance de session (Stickiness)

Comprendre comment garantir qu'un utilisateur reste sur le même serveur backend durant toute sa s...

Health Checks et Haute Disponibilité

Comment HAProxy détecte les pannes et gère le basculement automatique vers les serveurs sains.

Installation de HAProxy

Guide complet pour installer HAProxy sur les serveurs Linux (Debian, RedHat) et via des environne...

L'écosystème HAProxy : De l'Open Source à HAProxy One

Comprendre les différences, avantages et interconnexions entre HAProxy OSS, Enterprise, Fusion, E...

Bonnes Pratiques HAProxy : Optimisation, Sécurité et Haute Disponibilité

Découvrez les meilleures pratiques pour configurer HAProxy afin d'assurer performance, sécurité e...

Aide-mémoire HAProxy : Les commandes essentielles

Un guide pratique regroupant toutes les commandes indispensables pour installer, gérer, tester et...

HAProxy : Ajout et suppression dynamique de backends

Découvrez comment utiliser la Runtime API de HAProxy pour créer, configurer et supprimer des back...

ACME : Le guide du déploiement SSL/TLS automatisé

Comprendre le protocole ACME, ses avantages et comment configurer le renouvellement automatique d...

HAProxy : Guide détaillé des directives de configuration

Une exploration complète des directives essentielles de HAProxy : de bind à http-check, apprenez ...