blog.notmyidea.org/lets-encrypt-haproxy.html
2019-11-20 13:56:59 +01:00

268 lines
No EOL
15 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1">
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
<title>Let's Encrypt + HAProxy - Alexis - Carnets en ligne</title>
<meta charset="utf-8" />
<link href="https://blog.notmyidea.org/feeds/all.atom.xml" type="application/atom+xml" rel="alternate" title="Alexis - Carnets en ligne Full Atom Feed" />
<link rel="stylesheet" href="https://blog.notmyidea.org/theme/css/poole.css"/>
<link rel="stylesheet" href="https://blog.notmyidea.org/theme/css/syntax.css"/>
<link rel="stylesheet" href="https://blog.notmyidea.org/theme/css/lanyon.css"/>
<link rel="stylesheet" href="//fonts.googleapis.com/css?family=PT+Serif:400,400italic,700%7CPT+Sans:400">
<link rel="stylesheet" href="https://blog.notmyidea.org/theme/css/styles.css"/>
<style>
h1 {
font-family: "Avant Garde", Avantgarde, "Century Gothic", CenturyGothic, "AppleGothic", sans-serif;
padding: 80px 50px;
text-align: center;
text-transform: uppercase;
text-rendering: optimizeLegibility;
color: #202020;
letter-spacing: .1em;
text-shadow:
-1px -1px 1px #111,
2px 2px 1px #eaeaea;
}
#main {
text-align: justify;
text-justify: inter-word;
}
#main h1 {
padding: 10px;
}
.post-headline {
padding: 15px;
text-align: center;
}
</style>
</head>
<body>
<!-- Target for toggling the sidebar `.sidebar-checkbox` is for regular
styles, `#sidebar-checkbox` for behavior. -->
<input type="checkbox" class="sidebar-checkbox" id="sidebar-checkbox">
<!-- Toggleable sidebar -->
<div class="sidebar" id="sidebar">
<div class="sidebar-item">
<div class="profile">
<img src="https://blog.notmyidea.org/theme/img/profile.png"/>
</div>
</div>
<nav class="sidebar-nav">
<a class="sidebar-nav-item" href="/">Articles</a>
<a class="sidebar-nav-item" href="https://www.vieuxsinge.com">Brasserie du Vieux Singe</a>
<a class="sidebar-nav-item" href="http://blog.notmyidea.org/pages/about.html">A propos</a>
<a class="sidebar-nav-item" href="https://twitter.com/ametaireau">Messages courts</a>
<a class="sidebar-nav-item" href="https://github.com/almet">Code</a>
</nav>
</div> <div class="wrap">
<div class="masthead">
<div class="container">
<h3 class="masthead-title">
<a href="https://blog.notmyidea.org/" title="Home">Alexis - Carnets en ligne</a>
</h3>
</div>
</div>
<div class="container content">
<div id="main" class="posts">
<h1 class="post-title">Let's Encrypt + HAProxy</h1>
<span class="post-date">
11 février 2016, dans <a class="no-color" href="category/technologie.html">Technologie</a>
</span>
<img id="illustration" class="illustration-Technologie" src="" />
<div class="post article">
<h2 class="post-headline">Comment j'ai mis en place des certificats SSL avec Let's Encrypt derrière haproxy.</h2>
<div id="toc_container">
<div class="toc">
<ul>
<li><a href="#validation-des-domaines-par-lets-encrypt">Validation des domaines par Let's Encrypt</a></li>
<li><a href="#installation-des-certificats-dans-haproxy">Installation des certificats dans HAProxy</a></li>
<li><a href="#automatisation">Automatisation</a></li>
</ul>
</div>
</div>
<h1>🌟</h1>
<p><em>Note : Cet article n'est plus à jour. Il est maintenant (2018) possible d'installer des certificats SSL Let's Encrypt d'une manière beaucoup plus simple, en utilisant certbot (et le plugin nginx <code>certbot --nginx</code>).</em></p>
<blockquote>
<p>Its time for the Web to take a big step forward in terms of security
and privacy. We want to see HTTPS become the default. Lets Encrypt
was built to enable that by making it as easy as possible to get and
manage certificates.</p>
<p>-- <a href="https://letsencrypt.org/">Let's Encrypt</a></p>
</blockquote>
<p>Depuis début Décembre, la nouvelle <em>autorité de certification</em> Let's
Encrypt est passée en version <em>Beta</em>. Les certificats SSL sont un moyen
de 1. chiffrer la communication entre votre navigateur et le serveur et
2. un moyen d'être sur que le site Web auquel vous accédez est celui
auquel vous pensez vous connecter (pour éviter des <a href="https://fr.wikipedia.org/wiki/Attaque_de_l'homme_du_milieu">attaques de l'homme
du milieu</a>).</p>
<p>Jusqu'à maintenant, il était nécessaire de payer une entreprise pour
faire en sorte d'avoir des certificats qui évitent d'avoir ce genre
d'erreurs dans vos navigateurs:</p>
<p><img alt="Message de firefox lorsque une connexion n'est pas
sécurisée." src="%7Bfilename%7D/static/unsecure-connection.png"></p>
<p>Maintenant, grâce à Let's Encrypt il est possible d'avoir des
certificats SSL <strong>gratuits</strong>, ce qui représente un grand pas en avant
pour la sécurité de nos communications.</p>
<p>Je viens de mettre en place un procédé (assez simple) qui permet de
configurer votre serveur pour générer des certificats SSL valides avec
Let's Encrypt et le répartiteur de charge
<a href="http://www.haproxy.org/">HAProxy</a>.</p>
<p>Je me suis basé pour cet article sur
d'<a href="https://blog.infomee.fr/p/letsencrypt-haproxy">autres</a>
<a href="http://blog.victor-hery.com/article22/utiliser-let-s-encrypt-avec-haproxy">articles</a>,
dont je vous recommande la lecture pour un complément d'information.</p>
<h2 id="validation-des-domaines-par-lets-encrypt">Validation des domaines par Let's Encrypt</h2>
<p>Je vous passe les détails d'installation du client de Let's Encrypt, qui
sont <a href="https://github.com/letsencrypt/letsencrypt#installation">très bien expliqués sur leur
documentation</a>.</p>
<p>Une fois installé, vous allez taper une commande qui va ressembler à:</p>
<div class="highlight"><pre><span></span><span class="n">letsencrypt</span><span class="o">-</span><span class="n">auto</span> <span class="n">certonly</span> <span class="c1">--renew-by-default</span>
<span class="c1">--webroot -w /home/www/letsencrypt-requests/ \</span>
<span class="o">-</span><span class="n">d</span> <span class="n">hurl</span><span class="p">.</span><span class="n">kinto</span><span class="o">-</span><span class="k">storage</span><span class="p">.</span><span class="n">org</span> <span class="err">\</span>
<span class="o">-</span><span class="n">d</span> <span class="n">forums</span><span class="p">.</span><span class="n">kinto</span><span class="o">-</span><span class="k">storage</span><span class="p">.</span><span class="n">org</span>
</pre></div>
<p>Le <em>webroot</em> est l'endroit ou les preuves de détention du domaine vont
être déposées.</p>
<p>Lorsque les serveurs de Let's Encrypt vont vouloir vérifier que vous
êtes bien à l'origine des demandes de certificats, ils vont envoyer une
requête HTTP sur <code>http://domaine.org/.well-known/acme-challenge</code>, ou il
voudra trouver des informations qu'il aura généré via la commande
<code>letsencrypt-auto</code>.</p>
<p>J'ai choisi de faire une règle dans haproxy pour diriger toutes les
requêtes avec le chemin <code>.well-known/acme-challenge</code> vers un <em>backend</em>
nginx qui sert des fichiers statiques (ceux contenus dans
<code>/home/www/letsencrypt-requests/</code>).</p>
<p>Voici la section de la configuration de HAProxy (et <a href="https://github.com/almet/infra/blob/master/haproxy/haproxy.cfg#L63-L72">la configuration
complete</a>
si ça peut être utile):</p>
<div class="highlight"><pre><span></span><span class="nv">frontend</span> <span class="nv">http</span>
<span class="nv">bind</span> <span class="mi">0</span>.<span class="mi">0</span>.<span class="mi">0</span>.<span class="mi">0</span>:<span class="mi">80</span>
<span class="nv">mode</span> <span class="nv">http</span>
<span class="nv">default_backend</span> <span class="nv">nginx_server</span>
<span class="nv">acl</span> <span class="nv">letsencrypt_check</span> <span class="nv">path_beg</span> <span class="o">/</span>.<span class="nv">well</span><span class="o">-</span><span class="nv">known</span><span class="o">/</span><span class="nv">acme</span><span class="o">-</span><span class="nv">challenge</span>
<span class="nv">use_backend</span> <span class="nv">letsencrypt_backend</span> <span class="k">if</span> <span class="nv">letsencrypt_check</span>
<span class="nv">redirect</span> <span class="nv">scheme</span> <span class="nv">https</span> <span class="nv">code</span> <span class="mi">301</span> <span class="k">if</span> <span class="o">!</span>{ <span class="nv">ssl_fc</span> } <span class="o">!</span><span class="nv">letsencrypt_check</span>
<span class="nv">backend</span> <span class="nv">letsencrypt_backend</span>
<span class="nv">http</span><span class="o">-</span><span class="nv">request</span> <span class="nv">set</span><span class="o">-</span><span class="nv">header</span> <span class="nv">Host</span> <span class="nv">letsencrypt</span>.<span class="nv">requests</span>
<span class="nv">dispatch</span> <span class="mi">127</span>.<span class="mi">0</span>.<span class="mi">0</span>.<span class="mi">1</span>:<span class="mi">8000</span>
</pre></div>
<p>Et celle de NGINX:</p>
<div class="highlight"><pre><span></span><span class="n">server</span> <span class="err">{</span>
<span class="k">listen</span> <span class="mi">8000</span><span class="p">;</span>
<span class="k">server_name</span> <span class="n">letsencrypt</span><span class="p">.</span><span class="n">requests</span><span class="p">;</span>
<span class="n">root</span> <span class="o">/</span><span class="n">home</span><span class="o">/</span><span class="n">www</span><span class="o">/</span><span class="n">letsencrypt</span><span class="o">-</span><span class="n">requests</span><span class="p">;</span>
<span class="err">}</span>
</pre></div>
<h2 id="installation-des-certificats-dans-haproxy">Installation des certificats dans HAProxy</h2>
<p>Vos certificats SSL devraient être générés dans <code>/etc/letsencrypt/live</code>,
mais ils ne sont pas au format attendu par haproxy. Rien de grave, la
commande suivant convertit l'ensemble des certificats en une version
compatible avec
HAProxy:</p>
<div class="highlight"><pre><span></span><span class="n">cat</span> <span class="o">/</span><span class="n">etc</span><span class="o">/</span><span class="n">letsencrypt</span><span class="o">/</span><span class="n">live</span><span class="o">/</span><span class="n">domaine</span><span class="p">.</span><span class="n">org</span><span class="o">/</span><span class="n">privkey</span><span class="p">.</span><span class="n">pem</span> <span class="o">/</span><span class="n">etc</span><span class="o">/</span><span class="n">letsencrypt</span><span class="o">/</span><span class="n">live</span><span class="o">/</span><span class="n">domaine</span><span class="p">.</span><span class="n">org</span><span class="o">/</span><span class="n">fullchain</span><span class="p">.</span><span class="n">pem</span> <span class="o">&gt;</span> <span class="o">/</span><span class="n">etc</span><span class="o">/</span><span class="n">ssl</span><span class="o">/</span><span class="n">letsencrypt</span><span class="o">/</span><span class="n">domaine</span><span class="p">.</span><span class="n">org</span><span class="p">.</span><span class="n">pem</span>
</pre></div>
<p>Et ensuite dans la configuration de haproxy, pour le (nouveau)
<em>frontend</em> https:</p>
<div class="highlight"><pre><span></span><span class="n">bind</span> <span class="mi">0</span><span class="p">.</span><span class="mi">0</span><span class="p">.</span><span class="mi">0</span><span class="p">.</span><span class="mi">0</span><span class="p">:</span><span class="mi">443</span> <span class="n">ssl</span> <span class="k">no</span><span class="o">-</span><span class="n">sslv3</span> <span class="n">crt</span> <span class="o">/</span><span class="n">etc</span><span class="o">/</span><span class="n">ssl</span><span class="o">/</span><span class="n">letsencrypt</span>
</pre></div>
<p>Faites bien attention à avoir un <em>frontend</em> https pour tous vos sites en
HTTPS. <a href="https://github.com/almet/infra/blob/master/haproxy/haproxy.cfg#L38-L60">Pour moi cela ressemble à
ça</a>.</p>
<p>Une fois tout ceci fait, redémarrez votre service haproxy et zou !</p>
<h2 id="automatisation">Automatisation</h2>
<p>Pour automatiser un peu tout ça, j'ai choisi de faire ça comme suit:</p>
<ul>
<li>Un fichier domaine dans <code>letsencrypt/domains/domain.org</code> qui
contient le script <code>letsencrypt</code>.</li>
<li>Un fichier d'installation de certificats dans
<code>letsencrypt/install-certs.sh</code> qui s'occupe d'installer les
certificats déjà générés.</li>
</ul>
<p>Et voila ! <a href="https://github.com/almet/infra/">Le tout est dans un dépot
github</a>, si jamais ça peut vous servir,
tant mieux !</p>
</div>
</div>
</div>
<label for="sidebar-checkbox" class="sidebar-toggle"></label>
<script>
(function(document) {
var i = 0;
// snip empty header rows since markdown can't
var rows = document.querySelectorAll('tr');
for(i=0; i<rows.length; i++) {
var ths = rows[i].querySelectorAll('th');
var rowlen = rows[i].children.length;
if (ths.length > 0 && ths.length === rowlen) {
rows[i].remove();
}
}
})(document);
</script>
<script>
/* Lanyon & Poole are Copyright (c) 2014 Mark Otto. Adapted to Pelican 20141223 and extended a bit by @thomaswilley */
(function(document) {
var toggle = document.querySelector('.sidebar-toggle');
var sidebar = document.querySelector('#sidebar');
var checkbox = document.querySelector('#sidebar-checkbox');
document.addEventListener('click', function(e) {
var target = e.target;
if(!checkbox.checked ||
sidebar.contains(target) ||
(target === checkbox || target === toggle)) return;
checkbox.checked = false;
}, false);
})(document);
</script>
<!-- Piwik -->
<script type="text/javascript">
var _paq = _paq || [];
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u="//tracker.notmyidea.org/";
_paq.push(['setTrackerUrl', u+'piwik.php']);
_paq.push(['setSiteId', 3]);
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
})();
</script>
<noscript><p><img src="//tracker.notmyidea.org/piwik.php?idsite=3" style="border:0;" alt="" /></p></noscript>
<!-- End Piwik Code -->
</div>
</body>
</html>