Title: Utiliser Let's Encrypt avec Haproxy
subtitle: [FR]
Date: 2015-12-18 09:33
Modified: 2015-12-18 09:33
Category: Système
Tags: haproxy, hébergement, reverse proxy, sécurité, système
keywords: haproxy, hébergement, reverse proxy, sécurité, système
Slug: utiliser-letsencrypt-haproxy
Authors: Victor
Status: published
lang: fr

[TOC]

## De quoi parle-t-on donc ?

<p><strong>Note: </strong>This is the French version of the post. English version <a href="/2015/12/use-letsencrypt-haproxy.html">here.</a></p>

### Haproxy :

<p><a href="http://www.haproxy.org/">Haproxy </a>est un logiciel de proxy. Il peut servir à beaucoup de chose, ici nous l'utiliserons pour de l'https et de l'http. Je vous invite à lire <a href="http://blog.victor-hery.com/article21/configurer-un-reverse-proxy-sous-haproxy">mon article à ce sujet</a> si vous voulez en savoir plus.</p>

<p>Dans cet article, nous considérerons que vous avez un serveur avec Haproxy fonctionnel pour les tests.</p>

### Let's Encrypt :

<p><a href="https://letsencrypt.org/">Let's Encrypt</a> est un projet soutenu entre autre par la fondation Mozilla et Cisco.</p>

<p>L'idée est de mettre en place une autorité de certification gratuite pour créer des certificats SSL et permettre au plus grand nombre de personne de sécuriser leurs sites web.</p>

<p>Au regard du prix habituel d'un certificat, c'est un projet vraiment très intéressant !</p>

<p>D'autant plus qu'il est vraiment axé sur la facilité d'utilisation, avec notamment une API permettant de créer des certificats de manière simple.</p>

<p>Nous nous appuierons ici sur cette API, à travers un client créé par Let's Encrypt.</p>

<p><strong>EDIT : </strong>04/04/16 : ajout d'une note si vous utilisez des redirect de l'http vers l'https, pour permettre le renouvellement auto de letsencrypt</p>

<p><strong>EDIT</strong> : 16/09/16 : Mise à jour avec les nouveaux binaires suite à la sortie de bêta de LE + amélioration et versionning des Scripts</p>


## Concept

<p>Let's Encrypt propose plusieurs options via le client pour télécharger et valider un certificat SSL.</p>

<p>Si votre haproxy est sur le même serveur que le serveur web, vous pouvez utiliser l'option --webroot, qui permet de placer un fichier à la racine de votre site, que le site letsencrypt ira vérifier pour valider que vous possédez bien le site web. Si vous souhaitez utiliser cette technique, cet <a href="https://blog.infomee.fr/p/letsencrypt-haproxy">article de blog</a> explique très bien comment le faire interagir en utilisant un serveur apache dédié.</p>

<p>Dans cet article, nous utiliserons l'option --standalone qui permet de lancer un mini serveur web, qui contiendra le fichier de vérification et qui sera utilisé par le site letsencrypt. Cette option présente à première vue l'inconvénient de devoir utiliser le port 80 ou 443 pour lancer le serveur web, ce qui demande evidemment de faire sauter le serveur web principal, et donc de couper les sites pendant la vérification.</p>

<p>Mais nous allons utiliser une option du client qui permet d'utiliser un autre port que ceux par défaut, allié aux capacité frontend/backend de haproxy, pour effectuer la vérification sans aucune coupure de vos sites :-)</p>

<p>Merci à <a href="https://coolaj86.com/articles/lets-encrypt-with-haproxy/">coolaj86</a> dont l'article m'a donné cette idée d'utiliser haproxy et Let's Encrypt ensembles ;-)</p>

<p>-- Many thanks to <a href="https://coolaj86.com/articles/lets-encrypt-with-haproxy/">coolaj86</a> as his post give me this idea to use haproxy and Let's Encrypt together ;-) --</p>

<p>&nbsp;</p>

## Récupérer le client Let's Encrypt

<p>Maintenent que LE est officiellement sorti un binaire plus carré est disponible, et beaucoup plus simple à installer que le précédent letsencrypt-auto.</p>

<p>Toutes les info sont présente sur le <a href="https://certbot.eff.org/">site officiel</a> de certbot, mais voici les instructions rapides pour l'installer.</p>

<p><code>cd /root/</code></p>

<p><code>mkdir letsencrypt</code></p>

<p><code>cd letsencrypt</code></p>

<p><code>wget https://dl.eff.org/certbot-auto</code></p>

<p><code>chmod a+x certbot-auto</code></p>

<p><br />
Vous pouvez ensuite directement utiliser le binaire pour activer vos certificats</p>

<p><code>./certbot-auto certonly&nbsp; --domains blog.victor-hery.com --renew-by-default --http-01-port 63443 --agree-tos</code></p>

## Configurer haproxy

### Frontend

<p>Pour éviter toute coupure, nous allons utiliser votre (vos) frontend existant.</p>

<p>La requête de Let's Encrypt se fera sur l'adresse IP à laquelle répond le site web pour lequel vous générez le certificat, donc si vous avez plusieurs frontend ou plusieurs IP, il faudra configurer chaque frontend selon vos besoins.</p>

<p>L'idée est la suivante : lors de sa requête, Let's Encrypt interrogera l'url du site, suivi simplement de <em>/.well-known/acme-challenge/un-id_unique.</em></p>

<p>Nous allons donc configurer une acl qui cherchera cette chaine pour la rediriger vers un backend spécifique !</p>

```
frontend http-in
    acl app_letsencrypt  path_beg   /.well-known/acme-challenge/
    [...]
    use_backend bk-letsencrypt if app_letsencrypt
```

<ul>
	<li>path_beg : cherche les URL dont le path (ce qui est après le premier / de l'url) commence par <em>.well-known/acme-challenge/</em></li>
</ul>

<p>Ainsi, toutes les requêtes de vérification de Let's Encrypt seront redirigées vers le backend <em>bk-letsencrypt</em>.</p>

<p><strong>Attention :</strong> Si vous redirigez de manière forcée vos sites en HTTP vers l'HTTPS, alors haproxy va rediriger aussi les requêtes let's encrypt vers votre frontend HTTS.</p>

<p>Il faut alors ajouter l'acl et le use_backend bk-letsencrypt <strong>dans votre frontend https !</strong></p>

### Backend

<p>Concernant le backend, nous allons le configurer pour rediriger les requêtes vers le serveur qui sera lancé en local par le client Let's Encrypt.</p>

```
backend bk-letsencrypt
    log global
    mode http
    server srv_letsencrypt 127.0.0.1:63443
```

<ul>
	<li>mode http : permet, tant qu'à faire, de vérifier qu'il s'agit bien d'une requête http qui passe par ce backend</li>
	<li>server : la ligne redirige vers le serveur que le client Let's Encrypt aura lancé sur localhost, sur le port 63443</li>
</ul>

<p>Ce serveur ne tournera pas en permanence, uniquement lorsque le client Let's Encrypt est en attente de vérification, en temps normal haproxy renverra donc une erreur 503 si quelqu'un tente d'accéder à une URL qui correspond à l'acl du frontend.</p>

<p>Bien sûr, rechargez haproxy après ces modifications.</p>

```
systemctl reload haproxy.service
```

## Configurer et utiliser Let's Encrypt

### Configuration :

<p>Pour simplifier la ligne de commande et faciliter l'automatisation, nous allons directement configurer un fichier pour Let's Encrypt.</p>

<p>Let's Encrypt utilise par défaut le fichier <em>/etc/letsencrypt/cli.ini</em><em>. </em>Nous allons donc taper dedans directement.</p>

```
rsa-key-size = 4096
email = your_admin_email
authenticator = standalone
standalone-supported-challenges = http-01
```

<ul>
	<li>rsa-key-size ; permet de générer directement des certificats de 4096 bit, plus robustes que le 2048 par défaut. Vous pouvez redescendre à 2048 (mais pas en dessous !) si votre serveur est peu puissant pour gagner du temps de génération.</li>
	<li>email : utilisez une adresse valide, car ce sera l'adresse utilisée pour récupérer le certificat sur le site web&nbsp; de Let's Encrypt si jamais le besoin s'en faisait sentir</li>
	<li>authenticator : comme vu plus haut, nous utilisons le mode <em>standalone</em></li>
	<li>standalone-supported-challenges : Cette option est spécifique au mode standalone, et permet de spécifier la méthode à utiliser pour la vérification, parmi <em>http-01</em> ou <em>tls-sni-01</em>. Nous utilisons http-01 car notre site n'a pas (forcément) encore de certificat, et donc lors d'un appel sur 403 haproxy n'aura pas de certificat valide à présenter.</li>
</ul>

<p>Utiliser http pour la vérification ne pose pas de problème, car seule la requête de validation passe en clair, et elle n'a rien de secrète.</p>

### Génération du certificat

<p>La ligne de commande à utiliser pour générer votre certificat est la suivante :</p>

```
/root/letsencrypt/certbot-auto certonly --domains yourdomain.tld --renew-by-default --http-01-port 63443 --agree-tos
```

<ul>
	<li>certonly : précise que l'on souhaite simplement générer le certificat, et pas utiliser un plugin d'installation pour stocker les certificats quelque part</li>
	<li>domains : le domaine ou sous domaine pour lequel vous voulez générer ce certificat</li>
	<li>renew-by-default : indique que si le certificat existe déjà, il faut le renouveler. S'il n'existe pas, il sera créé dans la base de Let's Encrypt</li>
	<li>http-01-port : permet de spécifier le port à utiliser pour le serveur de validation temporaire. C'est le port utilisé dans le backend haproxy plus haut</li>
	<li>agree-tos : indique d'accepter les conditions d'utilisation de Let's Encrypt (vous les avez lues et êtes ok pour les accepter, pas vrai ?)</li>
</ul>

### Mettre en place le certificat

<p>Les certificats sont mis en place dans le répertoire <em>/etc/letsencrypt/live/yourdomain.tld/</em> par le client lors de la génération.</p>

<p>Vous y trouverez plusieurs fichiers :</p>

<ul>
	<li>cert.pem : le certificat (le crt)</li>
	<li>chain.pem : la chaine de confiance (les certificats de l'authorité)</li>
	<li>fullchain.pem : une concaténation des 2 premiers</li>
	<li>privkey.pem : la clef privée du certificat</li>
</ul>

<p>Pour haproxy, vous devez concaténer fullchain.pem et privkey.pem dans un seul fichier, et le placer là ou votre haproxy lit ses certificats.</p>

```
cat fullchain.pem privkey.pem &gt; domain.tld.pem
```

<p>Un exemple :</p>

```
frontend https-in
    bind  IP:443 ssl crt /etc/haproxy/cert/
```

<p>Ici, nous devons mettre notre fichier.pem dans le répertoire <em>/etc/haproxy/cert/</em></p>

<p>Une fois le certificat placé là, rechargez haproxy pour qu'il le lise, et ça y est tout sera Ok.</p>

<p>N'oubliez pas que pour que votre site fonctionne en HTTPS, il faudra un frontend https dans haproxy, avec les acl qui vont bien.</p>

<p>En général, un copier/coller de votre frontend HTTP classique en changeant le port vers 443 fait l'affaire.</p>

## Limitations

### Renouveler le certificat

<p>Même sorti de bêta, LE a pris la décision de ne fournir des certificat valides que 3 mois (90 jours), ce afin d'éviter les abus et faire "vivre" le certificat.</p>

<p>Notez que contrairement au binaire de bêta, certbot-auto peut scanner vos certificats disponibles (via le répertoire <em>/etc/letsencrypt/renewal/</em>) pour les renouveller automatiquement.</p>

<p>Pensez donc à configurer une tache cron sur votre serveur pour renouveler le certificat régulièrement</p>

```
crontab -e
#renew certificate
30 01 01,10,20,30 * * /root/letsencrypt/certbot-auto renew
```

<p>Cette tâche permettra de lancer la commande tous les 10 jours, afin d'être sur d'avoir des certificats à jour.</p>

<p>N'oubliez pas qu'il faudra quand même aller récupérer le fullchain.pem et le .key pour aller les mettre dans haproxy. Voyez plus bas pour un peu d'automatisation sur cette tâche !</p>

### Nombre de certificat par domaine

<p>A cause de sa gratuité, Let's Encrypt dispose d'un système évitant de générer trop violemment des certificats pour le même domaine.</p>

<p>Vous aurez donc une erreur si vous tentez de générer trop vite ou trop souvent des certificats avec le même domaine.</p>

<p><strong>Attention</strong>, c'est valable également pour les sous-domaine ! La limitation prend en compte tout ce qui se termine par domain.tld.</p>

### iDN :

<p>Actuellement Let's Encrypt ne gère pas les noms de domaines internationaux.</p>

<p>Il est donc impossible de générer un certificat pour un domaine ou un sous-domaine contenant des accents ou des caractères spéciaux.</p>

<p>Impossible par exemple de générer pour l'instant un certificat pour blog.héry.com malheureusement.</p>

<p>Une <a href="https://github.com/letsencrypt/boulder/issues/597">requête</a> existe actuellement à ce sujet sur le github de Let's Encrypt, mais plusieurs mois après le passage en stable, ce n'est toujours pas prêt malheureusement. Affaire à suivre (et à aider dans la mesure de ses moyens ;-) )</p>

## Bonus : des scripts

<p>Histoire de faciliter la génération et la mise en place sur haproxy, j'ai écris quelques petits scripts maison permettant de générer le certificat et le placer dans le bon répertoire, ainsi que gérer proprement le renouvellement.</p>

<p>Ceux-ci sont disponibles sur <a href="https://git.lecygnenoir.info/LecygneNoir/letsencrypt-haproxy">mon dépôt git</a>, vous pouvez donc directement les cloner sur votre serveur :</p>

<p><code>git clone https://git.lecygnenoir.info/LecygneNoir/letsencrypt-haproxy.git</code></p>

<p>Le README décrit rapidement comment utiliser les scripts, c'est globalement assez simple.</p>

<p>create_certificate permet de créer un certificat pour le domaine passé en paramètre, génère le .pem pour haproxy, le place dans l'arborescence haproxy et reload haproxy.</p>

<p>renew-certificates se contente de renouveler tous les certificats, de générer les fichiers pour haproxy et de reload ce dernier. Vous pouvez utiliser renew-certificates dans une tâche cron comme indiqué plus haut.</p>

<p><strong>Vérifiez les chemins dans les scripts, notamment où placer les certificats et le chemin vers le binaire certbot</strong></p>

<p>&nbsp;</p>

<p>Voila, avec tout ça vous devriez pouvoir générer autant de certificat que vous le souhaitez, et les utiliser directement dans haproxy, alors bienvenue dans le monde de l'HTTPS !</p>
