PROJET AUTOBLOG


IT-Connect

Site original : IT-Connect

⇐ retour index

PfSense : reverse proxy HTTPS avec HAProxy et ACME (Let’s Encrypt)

lundi 13 décembre 2021 à 17:15

I. Présentation

Dans ce tutoriel, nous allons voir comment configurer un reverse proxy HTTPS avec HAProxy sur PfSense. Pour le certificat du site, on utilisera ACME pour générer (et renouveler) automatiquement le certificat SSL avec Let's Encrypt.

HAProxy est une solution très complète et incontournable lorsque envisage de mettre en place un reverse proxy. Lors de l'utilisation d'un pare-feu PfSense sur un réseau, on peut ajouter la brique HAProxy par l'installation d'un simple paquet qu'il faudra ensuite configurer.

Démonstration au format vidéo disponible ci-dessous, avec le reverse proxy et un pool de deux serveurs Web pour le même site.

Pour cet exemple, je vais utiliser un serveur PfSense déjà configuré avec 2 interfaces (WAN et LAN), un serveur Web qui sera derrière le reverse proxy et qui contient le site Web WordPress à publier sur Internet, et un poste de travail distant (client en provenance d'Internet) pour tester le reverse proxy.

Ce qui donne le schéma suivant pour le site Internet "it-connect.tech" :

Dans la pratique :

1 - Le client tente de se connecter au site Internet "it-connect.tech", en HTTPS, il tombe sur HAProxy (sans s'en rendre compte).

2 - Le reverse proxy HAProxy traite la requête, il voit que le client veut accéder au site "it-connect.tech" donc il interroge le bon serveur Web (192.168.100.121/24), sur le port 80, car le serveur Web écoute sur ce port (on pourrait en utiliser un autre).

3 - Le serveur Web traite la requête du client, relayée par le reverse proxy (c'est le reverse proxy qui communique avec le serveur Web) et lui retourne une réponse (par exemple : le code source de la page demandée).

4 - Le reverse proxy retourne la page Web demandée au client, au sein d'une connexion sécurisée HTTPS.

II. Gérer les certificats Let's Encrypt sur PfSense

La première étape consiste à gérer les certificats SSL Let's Encrypt directement sur notre pare-feu PfSense. L'idée étant de générer le certificat initial, mais aussi de le renouveler automatiquement. La question que l'on peut se poser, c'est "pourquoi gérer le certificat SSL au niveau du reverse proxy plutôt que sur le serveur Web, voire même les serveurs web ?".

Le reverse proxy HTTPS va répondre aux requêtes HTTPS (comme son nom l'indique), alors c'est lui qui doit être en mesure de présenter au client le certificat SSL correspondant au domaine du site visité. Cela signifie qu'il doit héberger le certificat SSL.

Pour cela, on peut importer un certificat SSL obtenu auprès d'une autorité de certification en ligne et qui est valide pour une durée limitée (1 an, 2 ans, etc.). Sinon, l'alternative consiste à utiliser Let's Encrypt pour utiliser un certificat SSL gratuit, valide 90 jours à chaque fois, mais que l'on peut renouveler automatiquement (c'est ce que nous allons faire).

Imaginons que l'on ait une ferme de 2, 5 ou 10 serveurs Web pour le même site, cela signifie que lorsqu'un nouveau certificat SSL doit être déployé, il faut répéter l'opération autant de fois qu'il y a de serveurs Web. En gérant le certificat au niveau du reverse proxy, on limite aussi la maintenance.

A. Installation du paquet ACME sur PfSense

La première étape consiste à installer le paquet ACME. Sous le menu "System", cliquez sur "Package Manager" puis via l'onglet "Available Packages", recherchez et installez le paquet "acme".

Une fois que c'est fait, sous le menu "Services", cliquez sur "Acme Certificates".

Passons à la configuration.

B. Générer les clés ACME

Il faut que l'on commence par demander une clé d'authentification auprès de Let's Encrypt pour être autorisé à demander les certificats par la suite. Pour cela, cliquez sur l'onglet "Account Keys" et cliquez sur le bouton "Add".

Commencez par nommez cette clé, par exemple "certs.it-connect.tech" (le nom DNS n'a pas besoin d'être résolvable) et choisissez "Let's Encrypt Production ACME v2" au niveau de l'option "ACME Server".

Cliquez sur le bouton "Create new account key" pour générer une clé d'authentification et cela va remplir le champ "Account key" juste au-dessus. Nous devons enregistrer cette clé, donc je vous invite à cliquer sur "Register ACME account key". Normalement, un petit icône validé doit venir s'afficher sur le bouton, comme ceci :

Cliquez sur "Save" et vous obtenez ceci dans "Account keys" :

C. Demander un certificat Let's Encrypt depuis PfSense

Basculez sur l'onglet "Certificates", car nous allons demander notre premier certificat SSL Let's Encrypt pour notre site "it-connect.tech". Cliquez sur le bouton "Add".

Donnez un nom à ce certificat : le nom de domaine est une bonne idée donc ce sera "it-connect.tech" pour ma part. Choisissez le compte ACME que l'on vient de créer au niveau de l'option "Acme Account".

Ensuite, pour l'option "Domain SAN list", ajoutez une nouvelle entrée et choisissez la méthode "DNS-Manual". De cette façon, on va créer un enregistrement DNS par la suite pour prouver que l'on est bien propriétaire du nom de domaine. Pensez à renseigner l'option "Domainname" pour préciser le nom de domaine : pour ma part "it-connect.tech", car c'est le nom de domaine pour lequel je veux obtenir un certificat SSL.

Note : par défaut, le certificat est configuré pour se renouveler automatiquement tous les 60 jours (voir option "Certificate renewal after" en bas de page), tout en sachant qu'il est valide 90 jours à chaque fois.

Une fois que c'est fait, validez. Dans l'onglet "Certificates", votre certificat doit s'afficher (attention, il n'est pas généré pour le moment). Cliquez sur le bouton "Issue".

Suite à cette action, on peut voir que l'ACME nous demande de créer un enregistrement DNS TXT avec le nom "_acme-challenge" et une valeur spécifique. Par exemple :

Sur l'interface où se situe la gestion de votre domaine, vous devez créer un nouvel enregistrement DNS de type "TXT" avec les valeurs fournies par ACME, notamment le nom "_acme-challenge". Voici un exemple chez OVH :

Une fois que c'est fait, vous devez cliquer sur le bouton "Renew" comme précisé dans la sortie de la commande précédente.

Vous devriez obtenir une réponse positive (attention, même si c'est vert, parfois il y a des erreurs alors prenez le temps de regarder) qui se caractérise par la présence des lignes "Cert success" et "BEGIN CERTIFICATE", puis tout ce qui suit.

Mon certificat SSL Let's Encrypt pour "it-connect.tech" a été généré avec succès et l'emplacement des fichiers est précisé dans les logs :

Your cert is in /tmp/acme/it-connect.tech//it-connect.tech/it-connect.tech.cer 
Your cert key is in /tmp/acme/it-connect.tech//it-connect.tech/it-connect.tech.key 
The intermediate CA cert is in /tmp/acme/it-connect.tech//it-connect.tech/ca.cer 
And the full chain certs is there: /tmp/acme/it-connect.tech//it-connect.tech/fullchain.cer

Pour finir la partie certificat, cliquez sur l'onglet "General Settings" et cochez l'option "Cron Entry" pour activer la tâche planifiée (dans la crontab) afin de le renouveler automatiquement.

Ce certificat va pour voir être présenté au client qui voudront se connecter au site it-connect.tech, afin de sécuriser la connexion, et cela sera fait par HAProxy. En parlant d'HAProxy, passons à la configuration du reverse proxy.

III. Reverse proxy HTTPS HAProxy sur PfSense

A. Installation du paquet HAProxy sur PfSense

Sur le même principe que le paquet "acme", installez le paquet "haproxy" sur votre serveur PfSense.

B. Configuration générale de HAProxy

Commençons par l'onglet "Settings" de la configuration de HAProxy. Pour accéder à la configuration de HAProxy, sous le menu "Services", cliquez sur "HAProxy" tout simplement.

Ensuite, il faut renseigner le champ "Maximum connections", c'est-à-dire le nombre de connexions maximales par processus. Il faut ajuster ce paramètre en fonction du dimensionnement de votre serveur et de la fréquentation des ressources derrière le reverse proxy. On peut voir que 1 000 connexions consomment 48 Mo de mémoire, et en dessous on peut choisir le nom de processus à démarrer (1 par défaut / option "Number of processes to start").

Note : il n'est pas nécessaire de cocher l'option "Enable HAProxy" pour le moment, on va préparer la configuration avant.

Un peu plus bas dans la page, indiquez la taille 2048, car c'est une valeur recommandée pour l'option "Max SSL Diffie-Hellman size" (afin d'éviter d'avoir un avertissement dans les logs HAProxy).

C. Déclarer les serveurs backend

Lors de la configuration d'un reverse proxy, il faut configurer le Backend et le Frontend.

Le Backend, c'est ce qui se passe derrière le reverse proxy, cela correspond donc aux différents serveurs qui hébergent les ressources (par exemple, notre serveur Web avec le site it-connect.tech).

Le Frontend, c'est ce qui se passe en frontal sur le reverse proxy, c'est-à-dire de quelle façon le reverse proxy doit se présenter aux clients, et surtout comment il doit traiter les requêtes (par exemple, s'il reçoit une requête HTTPS à destination du domaine it-connect.tech, il doit savoir quoi en faire).

Commençons par le Backend. Cliquez sur l'onglet "Backend" puis sur le bouton "Add".

Cela va permettre de créer un pool de serveurs. Dans cet exemple, même si nous avons un seul serveur Web, on peut considérer que c'est notre pool pour le domaine it-connect.tech. D'ailleurs, on va utiliser ce nom pour notre pool (option "Name").

Ensuite, il faut renseigner l'option "Server list" : c'est là que l'on va déclarer les différents serveurs Web membre de ce pool, et donc qui héberge le site "it-connect.tech". Ajoutez un élément avec les options suivantes :

Ne cochez pas les options "Encrypt (SSL)" et tout ce qui s'en suit, sinon cela va nous créer des ennuis... Pour l'option "Client certificate", elle est utile seulement si le serveur Web est sur le port 443 en HTTPS, auquel cas il faut spécifier le certificat SSL, comme sur l'exemple ci-dessous. Dans cet exemple, ce n'est pas utile.

Descendez dans la page... Vous verrez qu'il y a énormément d'options. Par exemple, la partie "Loadbalancing Options" sert à définir comment le reverse proxy doit répartir les connexions entre les serveurs du pool actuel. Par défaut, c'est le mode classique appelé round-robin (c'est plus ou moins chacun son tour), mais il y a beaucoup d'autres modes. Ici, j'ai qu'un serveur Web donc la question ne se pose pas. Sinon, le reverse proxy joue le rôle de répartiteur de charge entre les serveurs.

Au sein de la section "Health checking", il est impératif de configurer l'option "Health check method". En fait, le reverse proxy va vérifier à intervalle régulier si notre serveur Web est opérationnel ou pas. Il faut lui indiquer comment effectuer cette vérification. Pour ma part, je choisis "HTTP" : cela implique que le serveur Web soit accessible en HTTP via son adresse IP afin que le reverse proxy puisse l'interroger.

Note : dans les logs du serveur Apache (access.log), vous allez voir une requête par seconde en provenance du reverse proxy, cela signifie qu'il vérifie l'état du serveur Web - Exemple : 192.168.100.1 - - [07/Dec/2021:17:47:54 +0100] "OPTIONS / HTTP/1.0" 200 110048"

Quel est l'intérêt de cette vérification ? Si un serveur Web de notre pool est hors ligne ou que le service Web est planté, le reverse proxy va en tenir compte et ne plus envoyer de requête à traiter à ce serveur Web, jusqu'à ce qu'il revienne à son état normal.

Continuez à descendre dans la page et cliquez sur "Save".

Au sein de la section "Backend", notre pool de serveurs apparaît. Cliquez sur "Apply Changes" pour appliquer la configuration.

Passons à la configuration du Frontend.

D. Déclarer le frontend dans HAProxy

Cliquez sur l'onglet "Frontend" puis sur le bouton "Add".

Nommez ce Frontend "it-connect.tech" puisque l'on va gérer les requêtes à destination de ce domaine. Veillez à ce que le statut ("Status") soit sur "Active".

Ensuite, il faut que l'on configure l'option "External address" de cette façon :

Un peu plus bas, sélectionnez l'option "http / https (offloading)" pour la valeur "Type". Cela veut dire que le reverse proxy va travailler au niveau de la couche HTTP/HTTPS.

Remarque : une alternative consiste à utiliser le mode "ssl / https (tcp mode)", mais dans ce cas, le reverse proxy travaille au niveau de la couche connexion avec le protocole TCP. Ce cas est utile si vous souhaitez gérer le certificat SSL au niveau des serveurs Web directement, mais ne permet pas l'activation de l'en-tête HTTP "X-FORWARDED-FOR". C'est utile aussi si vous utilisez le reverse proxy pour autre chose qu'un site Web.

PfSense - HAProxy Frontend

Passons à la section "Default backend, access control lists and actions". Cette section va permettre d'aiguillier les requêtes entre le Frontend et le Backend du reverse proxy. C'est ici que l'on va dire qu'une requête à destination du domaine "it-connect.tech" doit être redirigée vers notre Backend qui contient notre serveur Web.

Pour l'option "Access Control lists", ajoutez une ligne, c'est-à-dire une nouvelle règle (ACL). Comme ceci :

Pour définir ce que l'on doit faire lorsque cette règle matche, on va ajouter une action dans la section "Actions", comme ceci :

Vous avez aussi la possibilité de définir un Backend qui sera sélectionné par défaut, sans tenir compte de vos ACLs, au niveau de l'option "Default Backend". Néanmoins, si la requête ne correspond pas à "it-connect.tech", il n'y a pas de raison qu'elle soit traitée par notre Backend : il vaut mieux que le reverse proxy refuse la requête.

PfSense - HAProxy Backend

Descendez dans la page. Cochez l'option "Use forwardfor option" pour ajouter le champ "X-Forwarded-For" à l'en-tête HTTP. Pour rappel, cela permettra au serveur Web de connaître l'adresse IP d'origine du client, et pas seulement l'adresse IP du serveur reverse proxy.

Note : pour que l'adresse IP du client d'origine soit visible dans les logs Apache 2.4, vous devez activer le module "remoteip" et adapter le format des logs.

Descendez encore un peu... jusqu'à la section "SSL Offloading" puisqu'il faut choisir le certificat SSL Let's Encrypt au niveau de l'option "Certificate".

Voilà, c'est terminé pour la configuration du Frontend. Cliquez sur "Save". On obtient ceci :

Retournez dans l'onglet "Settings" afin d'activer HAProxy en cochant l'option "Enable HAProxy" puisque notre configuration est prête. Sauvegardez et cliquez sur "Apply changes" avant de passer à la suite.

E. Modifier le port de l'interface de gestion PfSense

Pour que notre reverse proxy HAProxy traite les requêtes qui arrivent sur le port 443 de l'interface WAN de PfSense, il faut que l'on crée une règle de pare-feu. Le problème, c'est que par défaut le port 443 est utilisé par défaut pour l'interface d'administration. Afin d'éviter un conflit (et potentiellement d'exposer l'interface d'administration PfSense), on va modifier le port utilisé.

Sous le menu "System", cliquez sur "Advanced". Dans l'onglet "Admin Access", modifiez l'option "TCP port" pour définir un autre port. Par exemple, le port 8443. Validez et accédez de nouveau à votre PfSense en spécifiant le nouveau port à la fin de l'URL : https://<adresse-IP>:8443.

F. Créer la règle de pare-feu pour HAProxy

Venons-en à la création de la règle de pare-feu pour HAProxy, ce dernier doit être en mesure de recevoir les requêtes sur le port 443. Pour cela, sous le menu "Firewall", cliquez sur "Rules" puis choisissez la zone "WAN".

Créez une nouvelle règle en cliquant sur le bouton "Add" et autorisez les flux HTTPS (443) vers le pare-feu afin qu'ils soient gérés par HAProxy. Ce qui donne :

Remarque : pour que nos flux HTTPS soient traités par notre reverse proxy, je ne veux pas voir de règles de NAT pour rediriger le port 443 vers le serveur Web interne. 😉 - Sinon, cela permettrait de bypasser le reverse proxy est d'atteindre directement le serveur Web, ce qui n'est pas le but : nous n'avons pas fait tout ça pour rien !

G. Les statistiques dans HAProxy

En soit, le reverse proxy est prêt : il est configuré et il peut recevoir ses premières requêtes. Néanmoins, avant de tester, je vous invite à regarder la partie statistique de HAProxy. Pour cela, retournez dans la configuration de HAProxy est spécifiez un port pour accéder à l'interface de statistiques (option "Internal stats port") : l'accès s'effectue seulement en local, via l'interface du PfSense.

Validez et appliquez les changements. Ensuite, toujours dans HAProxy, cliquez sur l'onglet "Stats" dans le menu (le menu "Stats FS" est équivalent, mais en plein écran). L'interface suivante va s'afficher :

Vous pouvez obtenir de nombreuses statistiques, et notamment l'état des différents serveurs de vos Backend. Ci-dessus, on peut voir que le serveur "debian-11" est en ligne, car la ligne est verte, et on peut savoir également combien de sessions il gère, etc...

Lorsqu'un serveur est inaccessible (cela signifie que notre vérification HTTP a échoué), alors la ligne devient rouge. En sélectionnant l'hôte via la case à cocher à gauche, on peut effectuer différentes actions notamment forcer la vérification de l'état de cet hôte ou encore passer l'hôte en mode maintenance ("Set state to MAINT"), ce qui permet de l'exclure du pool de serveurs pendant une opération de maintenance.

Maintenant, il ne vous reste plus qu'à accéder à votre site Internet positionné derrière le reverse proxy pour voir s'il fonctionne bien ! Je vous invite à tester en profondeur le site, notamment le mode visiteur, mais aussi le mode authentifié, en fonction de votre type de site. Pour finir ce tutoriel, quelques mots sur WordPress et Apache...

IV. WordPress derrière HAProxy

Au moment de tester, vous allez peut-être rencontrer quelques problèmes... Sachez que le problème ne vient pas forcément de HAProxy, mais peut-être du serveur Web voire même de WordPress (si vous utilisez WordPress...).

Lorsque vous avez un site WordPress positionné derrière HAProxy, accessible via HTTP en local, mais via HTTPS en externe, comme dans le cadre de cette configuration, vous allez surement rencontrer l'erreur "ERR_TOO_MANY_REDIRECTS" au sein du navigateur.

Que se passe-t-il ? Si le site est configuré avec une URL "HTTPS" dans les paramètres de WordPress et que le reverse proxy lui envoie une requête HTTP, WordPress va vouloir rediriger la requête en HTTPS. Sauf qu'en faisant ça, il va repasser par le reverse proxy qui va lui renvoyer la requête HTTP, et donc lui va vouloir rediriger en HTTPS, ce qui crée une boucle infinie. 🙂

Pour contourner ce problème, il faut que l'on crée une règle dans le fichier "wp-config.php" du site pour écrire l'URL du site en HTTPS et faire croire à WordPress qu'il travaille déjà en HTTPS. En complément, on va forcer l'utilisation du SSL au niveau de l'interface d'administration de WordPress, sinon vous allez obtenir un message d'accès refusé si vous tentez d'accéder au backoffice ou à votre profil une fois authentifié sur le site.

Au début du fichier wp-config.php (c'est important que ce soit au début), ajoutez ces lignes (remplacez le nom de domaine par votre site) :

if ( (!empty( $_SERVER['HTTP_X_FORWARDED_HOST'])) ||
(!empty( $_SERVER['HTTP_X_FORWARDED_FOR'])) ||
(!empty( $_SERVER['HTTP_X_FORWARDED_PROTO']) && strtoupper($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'HTTPS' ) ) {

  define('WP_HOME', 'https://it-connect.tech');
  define('WP_SITEURL', 'https://it-connect.tech');
  $_SERVER['HTTPS'] = 'on';
}

define('FORCE_SSL_ADMIN', true);

WordPress - Reverse Proxy HTTPS via HAProxy

Sauvegardez et le tour est joué, votre site WordPress doit fonctionner derrière le reverse proxy ! Ce qui s'applique à WordPress ne s'applique peut-être pas forcément à d'autres applications Web, et certainement pas à un site statique tout simple, mais c'est à connaître.

Désormais, les visiteurs du site it-connect.tech accèdent au site en HTTPS par l'intermédiaire du serveur HAProxy : mission accomplie.

The post PfSense : reverse proxy HTTPS avec HAProxy et ACME (Let’s Encrypt) first appeared on IT-Connect.