<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Tls on Guillaume Delré</title><link>https://guillaumedelre.github.io/fr/tags/tls/</link><description>Recent content in Tls on Guillaume Delré</description><generator>Hugo</generator><language>fr-FR</language><lastBuildDate>Thu, 17 Apr 2025 00:00:00 +0000</lastBuildDate><atom:link href="https://guillaumedelre.github.io/fr/tags/tls/index.xml" rel="self" type="application/rss+xml"/><item><title>HTTPS local avec Traefik: traefik.me est mort, vive sslip.io</title><link>https://guillaumedelre.github.io/fr/2025/04/17/https-local-avec-traefik-traefik.me-est-mort-vive-sslip.io/</link><pubDate>Thu, 17 Apr 2025 00:00:00 +0000</pubDate><guid>https://guillaumedelre.github.io/fr/2025/04/17/https-local-avec-traefik-traefik.me-est-mort-vive-sslip.io/</guid><description>Le certificat wildcard de traefik.me a été révoqué en 2025. Voici comment le remplacer avec sslip.io, mkcert et une configuration Traefik locale.</description><content:encoded><![CDATA[<p>La configuration semblait parfaite. Pointer <code>*.traefik.me</code> sur 127.0.0.1, télécharger un certificat wildcard depuis le même domaine, le déposer dans Traefik, et chaque service local obtient une URL HTTPS propre sans IP dans la barre d&rsquo;adresse. Pas de limites de débit Let&rsquo;s Encrypt, pas de <code>mkcert</code> à expliquer aux collègues, pas d&rsquo;avertissements de certificat auto-signé à contourner. Juste <code>https://myapp.traefik.me</code> et un cadenas vert.</p>
<p>Puis en mars 2025, Let&rsquo;s Encrypt a révoqué le certificat. Le wildcard cert pour traefik.me est parti et il ne reviendra pas.</p>
<h2 id="ce-que-traefikme-vendait-vraiment">Ce que traefik.me vendait vraiment</h2>
<p>traefik.me est un résolveur DNS wildcard. Tapez <code>anything.traefik.me</code> et ça résout vers 127.0.0.1. Tapez <code>anything.10.0.0.1.traefik.me</code> et ça résout vers 10.0.0.1. Aucun compte, aucune configuration, aucune infrastructure à maintenir. La partie DNS fonctionne toujours bien, soit dit en passant.</p>
<p>Le certificat était le bonus: un wildcard cert pour <code>*.traefik.me</code> que pyrou, le mainteneur, avait généré avec Let&rsquo;s Encrypt et distribué sur <code>https://traefik.me/cert.pem</code> et <code>https://traefik.me/privkey.pem</code>. C&rsquo;était pratique précisément parce que c&rsquo;était partagé: télécharger, déposer dans Traefik, terminé.</p>
<p>Partager une clé privée, c&rsquo;est ce qui l&rsquo;a tué.</p>
<p>Les Baseline Requirements du CA/Browser Forum, section 9.6.3, exigent que les souscripteurs &ldquo;maintiennent le contrôle exclusif&rdquo; de leur clé privée. La distribuer à quiconque visite une URL, c&rsquo;est exactement le contraire du contrôle exclusif. Let&rsquo;s Encrypt a envoyé une notification, bloqué toute future émission pour le domaine, et révoqué le certificat existant. Pyrou a confirmé la situation et recommandé mkcert comme alternative. Le projet survivra uniquement en tant que résolveur DNS.</p>
<p>Le cert avait déjà été révoqué deux fois avant 2025. La troisième était la dernière.</p>
<h2 id="sslipio-fait-la-même-chose-différemment">sslip.io fait la même chose, différemment</h2>
<p>sslip.io est aussi un résolveur DNS wildcard, avec une différence: l&rsquo;IP est encodée dans le hostname plutôt que résolue depuis un fallback. <code>10-0-0-1.sslip.io</code> résout vers <code>10.0.0.1</code>. <code>myapp.192-168-1-10.sslip.io</code> résout vers <code>192.168.1.10</code>. IPv6 fonctionne aussi.</p>
<p>L&rsquo;infrastructure derrière sslip.io est aussi plus visible: trois serveurs de noms à Singapour, aux États-Unis et en Pologne, traitant plus de 10 000 requêtes par seconde, avec un monitoring public. Environ 1 000 étoiles GitHub et une maintenance active sous licence Apache 2.0.</p>
<p>En mettant de côté l&rsquo;histoire des certificats, la comparaison est assez directe:</p>
<table>
  <thead>
      <tr>
          <th></th>
          <th>traefik.me</th>
          <th>sslip.io</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>DNS wildcard</td>
          <td>oui</td>
          <td>oui</td>
      </tr>
      <tr>
          <td>Fallback vers 127.0.0.1</td>
          <td>oui</td>
          <td>non</td>
      </tr>
      <tr>
          <td>IPv6</td>
          <td>non</td>
          <td>oui</td>
      </tr>
      <tr>
          <td>Certificat wildcard</td>
          <td><del>oui</del> révoqué</td>
          <td>non</td>
      </tr>
      <tr>
          <td>Infrastructure</td>
          <td>opaque</td>
          <td>documentée</td>
      </tr>
      <tr>
          <td>Activité du projet</td>
          <td>au point mort</td>
          <td>active</td>
      </tr>
  </tbody>
</table>
<p>Le seul avantage restant de traefik.me est le fallback vers 127.0.0.1: des URLs sans segment IP. Ça compte si on tient vraiment à <code>myapp.traefik.me</code> plutôt que <code>myapp.127-0-0-1.sslip.io</code>. La question est de savoir si cette différence vaut l&rsquo;incertitude sur l&rsquo;infrastructure.</p>
<h2 id="mkcert-comble-le-vide">mkcert comble le vide</h2>
<p>mkcert crée une autorité de certification locale, l&rsquo;installe dans le trust store système et dans les navigateurs qu&rsquo;il trouve, puis émet des certificats signés par cette CA. Les navigateurs voient une chaîne de confiance valide. Aucun avertissement, aucun clic, aucun &ldquo;continuer quand même&rdquo;.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>mkcert -install
</span></span></code></pre></div><p>C&rsquo;est la configuration unique. Ensuite, générer un certificat se fait en une commande:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>mkcert <span style="color:#e6db74">&#34;*.127-0-0-1.sslip.io&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># produit _wildcard.127-0-0-1.sslip.io.pem</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">#         _wildcard.127-0-0-1.sslip.io-key.pem</span>
</span></span></code></pre></div><p>La limitation: la CA de mkcert est locale. Les autres machines du réseau ne lui feront pas confiance par défaut. Pour un setup solo, c&rsquo;est très bien. Pour un environnement d&rsquo;équipe partagé, il faudrait distribuer la CA root, ce qui est essentiellement le même problème opérationnel que traefik.me tentait d&rsquo;éviter, juste à plus petite échelle.</p>
<h2 id="la-configuration-traefik">La configuration Traefik</h2>
<p>Le setup est le même quelle que soit la solution DNS choisie. Traefik a besoin du certificat monté en volume et d&rsquo;un file provider statique pointant vers un fichier de configuration TLS.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#75715e"># traefik/config/tls.yml</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">tls</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">certificates</span>:
</span></span><span style="display:flex;"><span>    - <span style="color:#f92672">certFile</span>: <span style="color:#ae81ff">/certs/cert.pem</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">keyFile</span>: <span style="color:#ae81ff">/certs/key.pem</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">stores</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">default</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">defaultCertificate</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">certFile</span>: <span style="color:#ae81ff">/certs/cert.pem</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">keyFile</span>: <span style="color:#ae81ff">/certs/key.pem</span>
</span></span></code></pre></div><p>La bonne pratique: faire tourner Traefik dans son propre projet Compose, séparé des services qu&rsquo;il route. Chaque projet de service se connecte à Traefik via un réseau externe partagé. On démarre et arrête les services indépendamment sans toucher au reverse proxy.</p>
<p>On commence par créer le réseau externe une seule fois:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker network create traefik-public
</span></span></code></pre></div><p><strong><code>traefik/compose.yml</code></strong> - Traefik seul, propriétaire du réseau:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">services</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">traefik</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">traefik:v3</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">ports</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;80:80&#34;</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;443:443&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">volumes</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">/var/run/docker.sock:/var/run/docker.sock</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">./config:/etc/traefik/config</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">./certs:/certs</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">command</span>:
</span></span><span style="display:flex;"><span>      - --<span style="color:#ae81ff">entrypoints.web.address=:80</span>
</span></span><span style="display:flex;"><span>      - --<span style="color:#ae81ff">entrypoints.websecure.address=:443</span>
</span></span><span style="display:flex;"><span>      - --<span style="color:#ae81ff">providers.docker=true</span>
</span></span><span style="display:flex;"><span>      - --<span style="color:#ae81ff">providers.docker.network=traefik-public</span>
</span></span><span style="display:flex;"><span>      - --<span style="color:#ae81ff">providers.file.directory=/etc/traefik/config</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">networks</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">traefik-public</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">networks</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">traefik-public</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">external</span>: <span style="color:#66d9ef">true</span>
</span></span></code></pre></div><p>On copie la sortie de mkcert dans <code>./certs/</code>, on renomme en <code>cert.pem</code> et <code>key.pem</code>, puis:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker compose -f traefik/compose.yml up -d
</span></span></code></pre></div><p>Traefik est lancé, il écoute sur le port 80 et 443, et surveille Docker pour les nouveaux containers. Aucune route n&rsquo;est encore configurée.</p>
<p><strong><code>whoami/compose.yml</code></strong> - un service qui rejoint le même réseau:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">services</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">whoami</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">traefik/whoami</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">labels</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;traefik.enable=true&#34;</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;traefik.http.routers.whoami.rule=Host(`whoami.127-0-0-1.sslip.io`)&#34;</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;traefik.http.routers.whoami.tls=true&#34;</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;traefik.http.routers.whoami.entrypoints=websecure&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">networks</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">traefik-public</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">networks</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">traefik-public</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">external</span>: <span style="color:#66d9ef">true</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker compose -f whoami/compose.yml up -d
</span></span></code></pre></div><p>Traefik détecte le nouveau container via le Docker provider, lit ses labels, et ajoute la route. <code>https://whoami.127-0-0-1.sslip.io</code> répond immédiatement. Arrêter <code>whoami</code> et la route disparaît. Traefik continue de tourner sans s&rsquo;en apercevoir.</p>
<p>La déclaration <code>external: true</code> est la ligne qui porte tout le poids. Sans elle, Compose crée un réseau limité au périmètre du projet: Traefik et <code>whoami</code> se retrouvent sur des réseaux différents et ne peuvent pas communiquer, même s&rsquo;ils tournent tous les deux. Le réseau externe est le bus partagé auquel chaque projet de service doit explicitement adhérer.</p>
<p>Si on préfère les URLs traefik.me, il suffit de remplacer la commande mkcert et le label de host:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>mkcert <span style="color:#e6db74">&#34;*.traefik.me&#34;</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span>- <span style="color:#e6db74">&#34;traefik.http.routers.whoami.rule=Host(`whoami.traefik.me`)&#34;</span>
</span></span></code></pre></div><p>Le fallback DNS vers 127.0.0.1 gère le reste.</p>
<h2 id="ce-que-lhistoire-traefikme-enseigne-vraiment">Ce que l&rsquo;histoire traefik.me enseigne vraiment</h2>
<p>Le modèle de distribution de certificats a toujours été fragile. Une &ldquo;paire clé publique-clé privée&rdquo; est une contradiction dans les termes. Chaque révocation était un avertissement que la suivante pourrait être définitive. Finalement, ça l&rsquo;a été.</p>
<p>La leçon ne se limite pas à traefik.me. Tout service qui apporte de la commodité en supprimant discrètement une frontière de sécurité finira par se heurter à cette frontière. mkcert est le bon outil pour ce problème parce qu&rsquo;il opère entièrement dans votre propre domaine de confiance: on génère la CA, on l&rsquo;installe, on émet les certificats. Rien ne dépend de la volonté continue d&rsquo;un tiers de contourner les règles d&rsquo;émission de certificats.</p>
<p>sslip.io résout proprement la partie DNS. mkcert résout proprement la partie TLS. Ils se combinent bien. Le setup traefik.me était plus simple, pendant un temps. Jusqu&rsquo;à ce que ce ne soit plus le cas.</p>
]]></content:encoded></item></channel></rss>