Pour vérifier l'identité d'un backend avec HAProxy 3.4, déclarez sur la ligne
server quatre éléments : ssl verify required, ca-file, sni et
verifyhost. Sans sni, la vérification échoue, avec un symptôme qui ne
l'évoque pas du tout. Cette leçon s'adresse à qui publie déjà un service
derrière HAProxy et veut que le proxy sache à qui il parle (le backend),
et de qui vient la requête (la source). Elle ne refait pas la terminaison
TLS vue dans Publier en HTTPS avec
HAProxy : elle enseigne comment
établir la confiance, dans les deux sens.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »La leçon part d'une chaîne qui répond sans rien vérifier et arrive à une chaîne dont chaque identité est contrôlée.
- Activer la vérification du certificat d'un backend avec
verify required. - Expliquer pourquoi
ca-fileetverifyhostne suffisent pas sanssni. - Reconnaître une autorité de certification sans
keyUsageavecopenssl. - Interpréter
SC--etssl_bc_err_strpour relier un 503 à sa vraie cause. - Distinguer un client avec certificat valide, sans certificat, ou signé par une autre autorité.
- Empêcher un client de choisir son adresse par en-tête ou par protocole PROXY.
Prérequis
Section intitulée « Prérequis »Les gestes ont été joués sur HAProxy 3.4.7, le paquet du dépôt
trixie-backports-3.4 de Debian 13. Vous avez besoin d'un HAProxy qui
tourne, d'un compte capable d'utiliser sudo et d'un backend qui parle TLS.
Les tableaux et les codes de retour reprennent les mesures du banc de la
leçon. Les extraits de configuration en reprennent la forme, avec des noms
neutres : ils n'ont pas été rejoués tels quels, et la page le dit quand une
sortie vient d'une exécution précise.
- Installer HAProxy 3.4 et lire ses sections : Installer HAProxy et lire ses sections de configuration.
- Servir un site en HTTPS et comprendre le SNI : Publier en HTTPS avec HAProxy.
- Lire une erreur de certificat avec
openssl s_client: Diagnostic TLS : déboguer les erreurs SSL avec openssl. - Suivre le trajet d'une requête,
HostetX-Forwarded-Forcompris : Publier un service web : le trajet d'une requête jusqu'au backend.
Pourquoi un proxy qui chiffre vers son backend peut-il ne rien vérifier ?
Section intitulée « Pourquoi un proxy qui chiffre vers son backend peut-il ne rien vérifier ? »Chiffrer une liaison ne dit rien de l'identité de celui qui est au bout :
avec ssl verify none, HAProxy parle TLS à n'importe quel serveur, y compris
un imposteur. La liaison est confidentielle, mais le certificat présenté
n'est jamais regardé : un serveur qui porte le même nom que le légitime,
signé par une autre autorité, reçoit le trafic et renvoie une réponse
indiscernable d'un succès. C'est le piège de cette leçon : aucune erreur ne
s'affiche. Une chaîne de confiance entièrement débranchée ressemble
exactement à une chaîne qui fonctionne, et seul un contrôle négatif (un
backend qui doit être refusé et qui l'est) la distingue de l'autre.
La vérification porte sur deux identités. Celle du backend : le proxy vérifie que le certificat du serveur est signé par l'autorité qu'il attend, et qu'il porte le bon nom. Celle de la source : l'application derrière le proxy ne voit que l'adresse du proxy, donc elle croit des en-têtes que le proxy doit réécrire, et le client peut prouver qui il est par un certificat client. Les sections qui suivent prennent ces trois mécanismes dans l'ordre.
Comment HAProxy vérifie-t-il le certificat d'un backend ?
Section intitulée « Comment HAProxy vérifie-t-il le certificat d'un backend ? »La vérification d'un backend tient sur la ligne server : ssl active TLS,
verify required rend la vérification obligatoire, ca-file désigne
l'autorité de confiance, verifyhost impose le nom, et sni dit quel nom on
demande. Les trois premiers mots-clés disent « vérifie, et contre quoi » ;
verifyhost ajoute le contrôle du nom porté par le certificat, faute de
quoi un certificat valide pour un autre service passerait ; sni dit au
backend quel certificat présenter. Le fichier de ca-file ne doit contenir
que l'autorité des backends : y mettre celle des clients mélange deux
chaînes de confiance qui n'ont rien à voir.
Voici la forme mesurée sur le banc, avec un nom neutre. Elle est découpée
sur plusieurs lignes pour la lecture ; HAProxy la lit comme une seule
ligne server.
backend facturation server api1 10.0.0.21:8443 ssl verify required \ ca-file /etc/haproxy/pki/ca-backends.crt \ sni str(facturation.corp.test) \ verifyhost facturation.corp.testAprès un haproxy -c -f /etc/haproxy/haproxy.cfg et un rechargement, le
résultat attendu est une réponse du backend légitime. Le vrai test est
négatif : pointez temporairement le server vers un serveur dont le
certificat est signé par une autre autorité, et la réponse doit devenir une
erreur. Si elle reste un succès, la vérification n'est pas stricte.
Pourquoi un verify required échoue-t-il sans sni ?
Section intitulée « Pourquoi un verify required échoue-t-il sans sni ? »Sans sni, un verify required échoue, même avec le bon ca-file et le
bon verifyhost : HAProxy 3.4.7 rend un 503 alors que le serveur est
UP. Un serveur TLS qui porte plusieurs certificats ne peut pas deviner
lequel présenter : il attend que le client annonce le nom demandé dans le
SNI (Server Name Indication, le nom d'hôte placé en clair dans le début de la
poignée de main TLS). Sans cette annonce, le proxy ne reçoit pas le certificat
attendu, la vérification échoue, et le trafic n'est pas servi. verifyhost
règle ce que l'on contrôle ; sni règle ce que l'on demande, et les
deux sont nécessaires.
La mesure a été faite sur un banc minimal, HAProxy 3.4.7, quatre
configurations de la ligne server face au même backend :
Ligne server | Résultat |
|---|---|
ssl verify required ca-file ca.crt verifyhost nom | 503 |
ssl verify required ca-file ca.crt | 503 |
ssl verify required ca-file ca.crt sni str(nom) verifyhost nom | 200 |
ssl verify none | 200 |
Le résultat est le même avec un backend Python et avec un backend
nginx : ce n'est donc pas le serveur. Les hypothèses voisines ont été
écartées une par une : ni verifyhost, ni l'extendedKeyUsage de la feuille,
ni la version de TLS, ni le nom de l'autorité n'expliquent l'échec. Le seul
changement qui fait passer de 503 à 200 est l'ajout de sni. Notez la dernière ligne : verify none répond 200 sans rien vérifier, ce qui explique que la faute passe
inaperçue tant qu'on ne vérifie pas.
Une précision pour la 3.4 : depuis la 3.3, HAProxy dérive par défaut le
SNI envoyé au serveur de l'en-tête Host de la requête (sni-auto). Cette
valeur change avec chaque client, alors que le nom du backend est fixe :
déclarez sni explicitement, c'est la forme qui a été mesurée.
Pourquoi une autorité sans keyUsage garde-t-elle le serveur DOWN ?
Section intitulée « Pourquoi une autorité sans keyUsage garde-t-elle le serveur DOWN ? »Une autorité de certification fabriquée sans extension keyUsage passe
openssl verify mais échoue dès que la vérification est stricte, ce
qu'exige un verify required : le serveur reste DOWN et le proxy rend
503. Le symptôme accuse le routage ou le backend, alors que la faute est dans
la PKI (l'infrastructure qui fabrique et signe les certificats). L'extension
keyUsage dit à quoi sert la clé de l'autorité : signer des certificats.
Une autorité qui ne la déclare pas est tolérée par les contrôles légers et
refusée par les contrôles stricts.
La fausse piste naturelle est l'extendedKeyUsage de la feuille (le
certificat du serveur) : elle n'y est pour rien dans cette mesure. Le bon
réflexe est de rejouer la vérification stricte avant de toucher à HAProxy :
openssl verify -x509_strict -purpose sslserver -CAfile ca-backends.crt feuille.crtSur le banc de la leçon, cette commande échoue pour une autorité sans
keyUsage et réussit avec. Avec OpenSSL 3.0.13, la même vérification,
rejouée pour cette page sur une autorité fabriquée sans l'extension, répond
« error 92 at 1 depth lookup: CA cert does not include key usage extension », alors que
openssl verify sans option rend OK. Pour fabriquer une autorité correcte
avec openssl req -x509, déclarez l'extension au moment de la création, par
exemple avec -addext "keyUsage=critical,keyCertSign,cRLSign", puis rejouez la
commande stricte ci-dessus : c'est elle qui valide.
Comment un 503 se lit-il avec SC-- et ssl_bc_err_str ?
Section intitulée « Comment un 503 se lit-il avec SC-- et ssl_bc_err_str ? »Le code de terminaison SC-- du journal dit que l'échec s'est produit à
l'établissement de la connexion, côté serveur ; le champ ssl_bc_err_str
donne la raison exacte donnée par OpenSSL. Le manuel de configuration 3.4,
section 8.5, définit S comme « the TCP session was unexpectedly aborted by
the server, or the server explicitly refused it » et C comme « the proxy was
waiting for the CONNECTION to establish ». Lus ensemble, ils disent que la
requête n'a jamais atteint l'application : le désaccord est dans la poignée de
main TLS avec le backend, pas dans le routage.
Le journal par défaut ne dit pas pourquoi. Ajoutez le champ
ssl_bc_err_str à un log-format pour obtenir la cause. Cette ligne
est donnée à titre d'exemple de structure : seul le résultat du champ a été
mesuré.
backend facturation log-format "%ci:%cp %ft %b/%s %ST %tsc %[ssl_bc_err_str]"Dans la mesure du banc, le champ rend « error:0A000086: certificate verify
failed » : la vérification du certificat a échoué, ce qui renvoie à
sni, au nom ou à l'autorité. Ce champ évite des heures de recherche, parce que le
503 et l'état du serveur ne distinguent pas ces causes. Le schéma ci-dessous
ordonne les trois questions à se poser : le serveur est-il DOWN, le journal
montre-t-il SC--, que dit ssl_bc_err_str.
Cette lecture se limite au défaut de confiance. La méthode générale de diagnostic d'un HAProxy qui ne répond pas dépasse le cadre de cette leçon, et fait l'objet de Diagnostiquer HAProxy sans masquer la cause.
Comment distinguer un client avec certificat, sans certificat et d'une autre autorité ?
Section intitulée « Comment distinguer un client avec certificat, sans certificat et d'une autre autorité ? »Pour reconnaître un client par son certificat sans fermer tout le site, mettez
verify optional sur le bind et décidez route par route avec ssl_c_used et
ssl_c_verify. Le bind porte ca-file : l'autorité des clients, qui
n'est pas celle des backends. Avec verify optional, la poignée de main aboutit
même sans certificat, ce qui laisse une route publique ouverte ; avec verify required, tout client sans certificat serait refusé dès la connexion, y
compris sur la route publique. L'autorisation se joue ensuite dans
l'application des règles : ssl_c_used dit si un certificat a été présenté, et
ssl_c_verify vaut 0 quand la chaîne est valide.
frontend entree bind :443 ssl crt /etc/haproxy/certs/site.pem \ ca-file /etc/haproxy/pki/ca-clients.crt verify optional http-request deny deny_status 403 if { path_beg /reserve/ } !{ ssl_c_used } http-request deny deny_status 403 if { path_beg /reserve/ } !{ ssl_c_verify 0 }Les deux règles couvrent deux échecs distincts : l'absence de certificat, et un certificat dont la chaîne n'est pas valide. Testez les trois cas : sans certificat, avec celui d'une autre autorité, avec celui de l'autorité des clients. Seul le dernier doit atteindre la route réservée, et la route publique doit répondre sans certificat. Ce que vous observez pour le cas de l'autre autorité (poignée de main refusée ou code d'erreur) se constate au banc : c'est le lab qui le fait mesurer.
Comment empêcher un client de choisir son adresse ?
Section intitulée « Comment empêcher un client de choisir son adresse ? »Un client ne doit jamais pouvoir choisir l'adresse que l'application lira :
remplacez X-Forwarded-For au lieu de l'allonger, et n'acceptez le protocole
PROXY que depuis une adresse de confiance. option forwardfor ajoute à
l'en-tête reçu : si le client envoie son propre X-Forwarded-For, sa valeur
arrive en premier chez l'application, qui lit presque toujours la première.
Le geste qui tranche est de remplacer : supprimer l'en-tête reçu avant
option forwardfor, ou le réécrire avec l'adresse source.
frontend entree http-request del-header X-Forwarded-For option forwardfor http-request set-header X-Forwarded-Proto https http-request set-header X-Client-DN %{+Q}[ssl_c_s_dn]La même règle vaut pour tout en-tête que l'application croit : le
protocole d'origine, et le nom porté par le certificat client, que la
dernière ligne transmet. Cette ligne vaut pour une route qui exige un
certificat. Sur une route publique, supprimez l'en-tête d'identité avec
http-request del-header X-Client-DN au lieu de le poser, sinon le client
l'envoie lui-même. Vous pouvez le vérifier avec
un backend qui renvoie ce qu'il a reçu : c'est lui le témoin, pas la
configuration du proxy.
L'autre porte est le protocole PROXY, qui permet à un répéteur en amont de
déclarer l'adresse du vrai client. Une écoute accept-proxy fait confiance à
quiconque s'y connecte, et l'en-tête PROXY précède la poignée de main
TLS : aucune vérification d'identité ne protège cette écoute, seule son
adresse le fait.
frontend relais bind 10.0.0.5:8444 accept-proxy ssl crt /etc/haproxy/certs/site.pemLiez l'écoute à une adresse joignable uniquement depuis la source
approuvée, pas à toutes les interfaces. Vérifiez ensuite deux choses : depuis
le réseau, l'écoute ne répond pas ; depuis la source approuvée, l'adresse
déclarée arrive jusqu'à l'application. Sans la seconde mesure, supprimer
l'écoute suffirait, et la configuration aurait perdu une capacité au lieu de
gagner un contrôle. La leçon Installer
HAProxy présente send-proxy, le
côté émetteur.
Mettre en pratique
Section intitulée « Mettre en pratique »Le lab part d'un HAProxy où tout répond alors que la confiance est débranchée : le backend est joint avec la vérification désactivée, aucune identité cliente n'est demandée, et l'adresse du client peut être choisie par en-tête comme par protocole PROXY. Vous rebranchez la chaîne à partir d'une recette qui décrit quatre autorités, des routes et des identités. La validation porte sur quatre mesures : l'identité du backend est vérifiée et un imposteur de même nom est refusé, une identité cliente valide est distinguée d'une absence et d'une autre autorité, un client ne peut pas choisir son adresse, et la route autorisée conserve protocole et identité jusqu'à l'application.
À retenir
Section intitulée « À retenir »Une chaîne de confiance se prouve par ses refus : un backend qui doit être rejeté, un client qui doit être refusé.
ssl verify nonechiffre sans vérifier : un imposteur de même nom répond comme le légitime, sans aucune erreur.- Un backend se vérifie avec
ssl verify required,ca-file,snietverifyhost:ca-filedit contre quoi,verifyhostquel nom contrôler,sniquel nom demander. - Sans
sni, unverify requiredéchoue : 503 sur HAProxy 3.4.7 avec un serveurUP, alors queca-fileetverifyhostsont corrects. - Une autorité sans
keyUsagepasseopenssl verifyet échoue en-x509_strict -purpose sslserver: le serveur resteDOWN, la faute est dans la PKI, pas dans le routage. SC--situe l'échec à l'établissement, côté serveur ;ssl_bc_err_str, dans lelog-format, donne la raison OpenSSL exacte.- Un client se reconnaît par
verify optionalsur lebind, puisssl_c_usedetssl_c_verify 0route par route. option forwardforajoute : supprimez ou réécrivez l'en-tête reçu, et faites de même pour tout en-tête d'identité que l'application croit.- Une écoute
accept-proxyse protège par son adresse, jamais par TLS, et se mesure des deux côtés.
Contrôle de connaissances
Section intitulée « Contrôle de connaissances »Huit questions vérifient que vous savez vérifier un backend, interpréter le symptôme d'un échec de confiance et fermer les portes par lesquelles une source choisit son identité, une fois le lab joué.
Contrôle de connaissances
Validez vos connaissances avec ce quiz interactif
Informations
- Le chronomètre démarre au clic sur Démarrer
- Questions à choix multiples, vrai/faux et réponses courtes
- Vous pouvez naviguer entre les questions
- Les résultats détaillés sont affichés à la fin
Lance le quiz et démarre le chronomètre
Vérification
(0/0)Score par domaine
Un domaine regroupe plusieurs guides et reçoit plusieurs questions : son score est plus fiable qu'un score par thème, qui porte souvent sur une seule question.
Bilan
Points forts
Aucun sujet réussi à 80 % sur au moins deux questions pour l’instant.
Points faibles
Aucun sujet sous le seuil de réussite.
À faire ensuite
Des indices pour retenter votre chance ?
Continuer le cours : Protéger et observer HAProxy
Nouveau quiz complet avec des questions aléatoires
Retravailler uniquement les questions ratées
Retour à la liste des certifications