From d5afd8bb26cdfaf51be04e260bf9e31edbd3bcb2 Mon Sep 17 00:00:00 2001 From: Yax <1949284+kianby@users.noreply.github.com> Date: Sun, 6 Mar 2022 15:54:32 +0100 Subject: [PATCH] new post --- posts/2022/2022-03-06-https-local.md | 168 +++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 posts/2022/2022-03-06-https-local.md diff --git a/posts/2022/2022-03-06-https-local.md b/posts/2022/2022-03-06-https-local.md new file mode 100644 index 0000000..78bd8bf --- /dev/null +++ b/posts/2022/2022-03-06-https-local.md @@ -0,0 +1,168 @@ + + + +Mes services sont hébergés sur un serveur de containers propulsé par docker compose. L'exposition des services HTTP et HTTPS est géré par le *reverse-proxy* [Traefik](https://traefik.io/traefik/) qui s'occupe aussi de renouveler les certificats SSL délivrés par Let's Encrypt ; pour cela il s'interface avec la plupart des *registrars* (les entités qui gère les noms de domaine). Cela permet de bénéficier de la méthode **dnsprovider** et de demander un certificat *wildcard* (*.mondomaine.fr) plutôt que des certificats pour chaque hôte du domaine (soit chaque container exposé). + +Un serveur à base de containers est facilement portable d'une machine à l'autre et on en vient vite à monter un environnement de test local sur sa machine pour tester / valider avant de déployer sur le serveur. Ce qui est plus *touchy* c'est de se placer dans des configurations similaires au serveur en production et notamment d'avoir du HTTPS. + +Après avoir considéré la complication à gérer des certificats auto-signés, j'ai opté pour une solution basée sur la résolution de noms fournie par [Traefik.me](https://traefik.me/). Cette géniale idée permet de résoudre n'importe quel nom de machine du domaine **traefik.me** en **localhost**. Contrairement à ce que le nom du site laisse supposer, ce n'est pas une solution officielle fournie par Traefik mais je crois que [son auteur Pyrou](https://github.com/pyrou) est un utilisateur (et peut-être un fan) de Traefik. En tout cas on peut mettre en œuvre traefik.me avec n'importe quelle autre solution de *reverse-proxy*, les certificats PEM à jour sont fournis sur la page d'accueil du site. + +Voici donc ma configuration locale pour résoudre les nom de mes containers en HTTPS sur le domaine traefik.me : + + +Fichier **docker-compose.traefik-local.yml** : + +```yaml +services: + traefik-local: + container_name: traefik-local + image: traefik:v2.5.3 + profiles: ["testing"] + ports: + - 80:80 + - 443:443 + - 8080:8080 + expose: + - 8080 + labels: + - traefik.enable=true + restart: unless-stopped + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + - traefik.yml:/etc/traefik/traefik.yml + - tls.yml:/etc/traefik/tls.yml + - certs:/etc/ssl/traefik + + traefik-reverse-proxy-https-helper: + container_name: traefik-reverse-proxy-https-helper + image: alpine + profiles: ["testing"] + command: sh -c "cd /etc/ssl/traefik + && wget traefik.me/cert.pem -O cert.pem + && wget traefik.me/privkey.pem -O privkey.pem" + volumes: + - certs:/etc/ssl/traefik + +volumes: + certs: +``` + +Fichier **tls.yml** : + +```yaml +tls: + stores: + default: + defaultCertificate: + certFile: /etc/ssl/traefik/cert.pem + keyFile: /etc/ssl/traefik/privkey.pem + certificates: + - certFile: /etc/ssl/traefik/cert.pem + keyFile: /etc/ssl/traefik/privkey.pem +``` + +Fichier **traefik.yml** : + +```yaml +logLevel: INFO + +api: + insecure: true + dashboard: true + +entryPoints: + http: + address: ":80" + https: + address: ":443" + +providers: + file: + filename: /etc/traefik/tls.yml + docker: + endpoint: unix:///var/run/docker.sock + watch: true + exposedByDefault: false + defaultRule: "HostRegexp(`{{ index .Labels \"com.docker.compose.service\"}}.traefik.me`,`{{ index .Labels \"com.docker.compose.service\"}}-{dashed-ip:.*}.traefik.me`)" + +http: + # global redirect to https + routers: + http-catchall: + rule: "hostregexp(`{host:.+}`)" + entrypoints: + - http + middlewares: + - redirect-to-https + + # middleware redirect + middlewares: + redirect-to-https: + redirectscheme: + scheme: https + permanent: true +``` + +On notera le container compagnon "traefik-reverse-proxy-https-helper" qui s'occupe de rapatrier une version à jour des certificats et de les stocker sur le volume **certs** partagé avec le container "traefik-local". + +La configuration de traefik pour le serveur est classique. Dans mon cas elle s'interface avec le registrar infomaniak qui me loue mon nom de domaine. + +Fichier **docker-compose.traefik-infomaniak.yml** : + +```yaml +services: + traefik-infomaniak: + container_name: traefik-infomaniak + image: traefik:v2.5.3 + profiles: ["production"] + command: + - --providers.docker=true + - --providers.docker.exposedbydefault=false + - --api.dashboard=false + - --entrypoints.http.address=:80 + - --entrypoints.https.address=:443 + - --certificatesresolvers.letsencrypt.acme.email=${LETSENCRYPT_EMAIL} + - --certificatesresolvers.letsencrypt.acme.storage=/acme.json + - --certificatesResolvers.letsencrypt.acme.dnsChallenge=true + - --certificatesresolvers.letsencrypt.acme.dnschallenge.provider=infomaniak + environment: + - INFOMANIAK_ACCESS_TOKEN=${LETSENCRYPT_DNSPROVIDER_TOKEN} + labels: + - traefik.enable=true + - traefik.http.routers.api.entrypoints=http + - traefik.http.routers.api.entrypoints=https + - traefik.http.routers.api.service=api@internal + # middleware auth + - traefik.http.routers.api.middlewares=auth + - traefik.http.middlewares.auth.basicauth.users=${BASIC_AUTH} + # request widlcard certificate + - traefik.http.routers.api.tls.certresolver=letsencrypt + - traefik.http.routers.api.tls.domains[0].main=${DOMAIN} + - traefik.http.routers.api.tls.domains[0].sans=*.${DOMAIN} + # global redirect to https + - traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`) + - traefik.http.routers.http-catchall.entrypoints=http + - traefik.http.routers.http-catchall.middlewares=redirect-to-https + # middleware redirect + - traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https + - traefik.http.middlewares.redirect-to-https.redirectscheme.permanent=true + ports: + - 80:80 + - 443:443 + restart: unless-stopped + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + - acme.json:/acme.json +``` + +Le support des profils de docker-compose permet de choisir la bonne configuration au démarrage des containers. + +En mode "production" sur le serveur : + + docker-compose --env-file .env --profile production up -d + +En mode "test" sur la machine locale : + + docker-compose --env-file .env --profile testing up + +Les configurations docker-compose de l'article sont un peu simplifiées pour faciliter la compréhension. Les sources complètes [sont sur GitHub](https://github.com/kianby/selfhosting).