Aller au contenu
English
Compte : non connecté, synchronisation possible Mon apprentissage
Selectionner le thème
English

Vérifier l'identité du backend et de la source

Par mis à jour le

Améliorer cette page

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.

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-file et verifyhost ne suffisent pas sans sni.
  • Reconnaître une autorité de certification sans keyUsage avec openssl.
  • Interpréter SC-- et ssl_bc_err_str pour 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.

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.

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.test

Aprè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 serverRésultat
ssl verify required ca-file ca.crt verifyhost nom503
ssl verify required ca-file ca.crt503
ssl verify required ca-file ca.crt sni str(nom) verifyhost nom200
ssl verify none200

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 :

Fenêtre de terminal
openssl verify -x509_strict -purpose sslserver -CAfile ca-backends.crt feuille.crt

Sur 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.

Arbre de décision pour un 503 vers un backend TLS : si le serveur est DOWN, contrôler la PKI avec openssl verify -x509_strict ; sinon, si le journal montre SC--, lire ssl_bc_err_str, et si la vérification du certificat a échoué, ajouter sni et verifyhost.503 sur une routevers un backend en TLSLe serveur est-ilDOWN ?Le journal montre-t-ilSC-- ?nonContrôler la PKI :openssl verify -x509_strict-purpose sslserverouiLire ssl_bc_err_strdans le journalouiAutre cause :routage, sonde, capaciténonAjouter sni et verifyhostsur la ligne servercertificate verify failed
Un serveur DOWN oriente vers la PKI, un SC-- avec un serveur UP oriente vers ssl_bc_err_str, puis vers sni. Source · SVG
Échap pour fermer, + et − pour zoomer, défilement pour se déplacer. 100 %

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.pem

Liez 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.

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.

Une chaîne de confiance se prouve par ses refus : un backend qui doit être rejeté, un client qui doit être refusé.

  • ssl verify none chiffre 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, sni et verifyhost : ca-file dit contre quoi, verifyhost quel nom contrôler, sni quel nom demander.
  • Sans sni, un verify required échoue : 503 sur HAProxy 3.4.7 avec un serveur UP, alors que ca-file et verifyhost sont corrects.
  • Une autorité sans keyUsage passe openssl verify et échoue en -x509_strict -purpose sslserver : le serveur reste DOWN, la faute est dans la PKI, pas dans le routage.
  • SC-- situe l'échec à l'établissement, côté serveur ; ssl_bc_err_str, dans le log-format, donne la raison OpenSSL exacte.
  • Un client se reconnaît par verify optional sur le bind, puis ssl_c_used et ssl_c_verify 0 route par route.
  • option forwardfor ajoute : 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-proxy se protège par son adresse, jamais par TLS, et se mesure des deux côtés.

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

8 questions
8 min.
70% requis

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

Ce projet vous est utile ?

Les guides, formations, quiz et labs restent gratuits. Si vous les utilisez régulièrement, vous pouvez contribuer à leur maintenance et à leur développement.

Devenir membre de soutien (nouvel onglet) Soutenir une fois (nouvel onglet) En savoir plus

Suivez aussi le projet sur LinkedIn