Aller au contenu principal

2 articles tagués avec « ubuntu »

Voir tous les tags

· 8 minutes de lecture
Jonas Turbeaux

/img/blog/traefik_docker_letsencrypt.png

Vous avez dit sauvage ?

Un certificat "wildcard" C'est un certificat qui répond à tous les sous-domaines d'un domaine. Par exemple, si vous avez un certificat wildcard pour le domaine *.example.com, il sera valide pour foo.example.com, bar.example.com, prout.example.com, etc.

Vous voyez le * ? C'est un caractère joker, qui signifie "n'importe quoi". C'est pour cela qu'on appelle ça un certificat wildcard, un sauvage.

Pourquoi faire ? Ben c'est quand même 'achement pratique si on doit générer des sites en mode Saas, software as a service. TiBillet, par exemple, est construit en mode multi-tenant. Cela veut dire un noyau unique pour plusieurs instances fédérées. Chaque instance est un tenant, et chaque tenant possède son propre sous-domaine.

Dans le cas d'un déploiement en mode "logiciel à la demande", c'est à dire avec des instances créées automatiquement en quelques clics, avoir un seul certificat valide pour les adresses comme https//raffinerie.tibillet.re/ ou https://rezom.tibillet.re/ (notez le s de https), c'est quand même assez chouette, non ?

Let's Encrypt et Traefik, l'ultra combo.

Pour convaincre Letsencrypt de nous donner un certificat wildcard, il faut faire un petit peu plus de chose que pour un certificat simple. En plus de lui prouver que nous avons bien la main sur le serveur qui répond à l'ip résolu par le nom de domaine, il faut ausi lui prouver que nous sommes les proprietaires de la totalité du domaine. Autrement dit : que nous avons les droits d'écritures de toute la zone DNS.

Pour cela, Letsencrypt va nous demander d'ajouter un champ TXT dans la zone DNS du domaine. Ce champ contient une clé créé par Letsencrypt, s'il arrive à le lire, il va donc considérer à raison que nous avons bien les droits d'écriture sur la zone DNS. Donc que nous sommes le proprio.

Le truc, c'est qu'un certificat doit se renouveller régulièrement, et que donc, il faut que ce champ TXT soit présent et différent à chaque renouvellement. Et on va pas se le cacher, c'est un peu contraignant et fastidieux de le faire à la main.

C'est la qu'intervient Traefik. Traefik est un reverse proxy, c'est à dire un serveur qui va rediriger les requêtes http vers le bon conteneur docker. Il est capable de faire plein de choses, mais ce qui nous intéresse ici, c'est qu'il est capable de gérer les certificats SSL, et même de renouveller automatiquement les widlcards.

Traefik et Letsencrypt fonctionnent merveilleusement bien ensemble. Le premier va poser la question au second, puis va modifier la zone DNS automatiquement pour que le champs TXT soit à jour régulièrement. Cela nécessite de donner les trois d'écriture à notre Zone à notre conteneur Traefik. Pas de soucis particuliers, l'instance Traefik est hebergé sur notre serveur, nous avons donc la main dessus..

Voyons comment mettre tout ça en place.

Prérequis

  • Un nom de domaine : Ici, nous allons voir la methode avec Gandi et avec OVH
  • Docker ( et docker-compose ) : https://docs.docker.com/install/
  • Traefik : https://docs.traefik.io/
  • Un serveur ou heberger tout ça avec une ip statique et les ports 80 et 433 corectement redirigé. On utilise des VPS sous Ubuntu, mais ça marche aussi avec une autre distribution ou même un raspberry pi.

Installation

Je vous invite à aller du coté d'une précédente note de blog qui détaille comment préparer votre serveur pour la suite : https://codecommun.coop/blog/sysadmin-mon-chaton-part1/

Une légère différence ceci, nous allons utiliser le fichier docker-compose.yml du dossier "wildcard" de notre dépot github Traefik : https://github.com/TiBillet/Traefik-reverse-proxy/tree/main/wildcard

Si vous avez déja lancé le docker-compose.yml de la note de blog, vous pouvez le stopper et le supprimer et utiliser celui-ci à la place.

Si vous n'avez de compte ni sous OVH ni chez Gandi, pas d'inquiétude, Traefik supporte beaucoup de registrar : https://doc.traefik.io/traefik/https/acme/?ref=j.hommet.net#dnschallenge

Commençons par créer un nouveau champ A vers l'ip de votre serveur, avec comme sous domaine *.

* 10800 IN A <IP>

Ensuite, allons générer une clé API pour donner les droits d'écriture dans cette zone à Traefik :

Avec OVH Cloud

Comme nous le disions, nous allons avoir besoin de donner les droits d'écriture à Traefik. Il vous faut bien sur un compte ovh valide et avoir acheté un nom de domaine.

  • Allez sur https://eu.api.ovh.com/createApp/

  • Logguez vous, créez une nouvelle app et récuperez les cred'

  • Dans le même dossier que le docker-compose, Créez un fichier .env et remplissez les deux premières variables avec les cred' récupérés précédemment.

OVH_APPLICATION_KEY=""
OVH_APPLICATION_SECRET=""
OVH_CONSUMER_KEY=""
  • Lancez cette commande curl pour donner les droits de modification à l'application. Remplacez OVH_APPLICATION_KEY et VOTRE_DNS, avec vos propres valeurs.
curl -XPOST -H"X-Ovh-Application: <OVH_APPLICATION_KEY>" -H "Content-type: application/json" \
https://eu.api.ovh.com/1.0/auth/credential -d '{
"accessRules": [
{
"method": "POST",
"path": "/domain/zone/<VOTRE_DNS>/record"
},
{
"method": "POST",
"path": "/domain/zone/<VOTRE_DNS>/refresh"
},
{
"method": "DELETE",
"path": "/domain/zone/<VOTRE_DNS>/record/*"
}
],
"redirection":"https://www.<VOTRE_DNS>/"
}'

Si vous n'avez pas curl, installez le. Sinon, vous pouvez aussi utiliser l'application en ligne de OVH. Je vous laisse découvrir par vous-même.

  • Copiez le consumer_key et rentrez la variable correspondante dans le .env
  • Validez la requete avec le lien envoyé dans la réponse. Pensez à mettre unlimited dans la durée des droits d'execution car Traefik renouvelle le widlcard tous les trois mois.

Avec Gandi.net

Un ptit peu plus simple du coté de Gandi, il suffit de générer une clé API dans votre compte user / Authentication option / API key.

Dans votre .env, ajoutez la variable suivante :

GANDI_API_KEY="PLOUFPLOUFDEVINEMOI"

Décollage

Completez votre .env avec EMAIL et DOMAIN, paske c'est le votre et pas le mien :

DOMAIN="pingoin-sauvage.coop"
EMAIL="tux42@pingoin-sauvage.coop"

Et voici le compose magique :

version: "3"
services:
traefik:
image: "traefik:saintmarcelin"
container_name: "traefik_wild"
restart: always
command:
- --log.level=DEBUG
- --api.insecure=true
- --providers.docker=true
- --providers.docker.exposedbydefault=false

- --entrypoints.web.address=:80
- --entrypoints.web.http.redirections.entrypoint.to=websecure
- --entrypoints.web.http.redirections.entrypoint.scheme=https

- --entrypoints.websecure.address=:443
- --entrypoints.websecure.http.tls=true
- --entrypoints.websecure.http.tls.certResolver=letsencrypt
- --entrypoints.websecure.http.tls.domains[0].main=${DOMAIN}
- --entrypoints.websecure.http.tls.domains[0].sans=*.${DOMAIN}

- --certificatesresolvers.letsencrypt.acme.dnschallenge=true
- --certificatesresolvers.letsencrypt.acme.dnschallenge.provider=gandiv5
- --certificatesresolvers.letsencrypt.acme.dnschallenge.delayBeforeCheck=60
- --certificatesResolvers.letsencrypt.acme.dnsChallenge.resolvers=1.1.1.1:53,8.8.8.8:53
- --certificatesresolvers.letsencrypt.acme.email=${EMAIL}
- --certificatesresolvers.letsencrypt.acme.storage=/dnschallenge/acme.json

- --certificatesresolvers.letsencrypt.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory

ports:
- "80:80"
- "443:443"
environment: # choisissez votre provider. Gardez ceux de Gandi, ou ceux d'ovh, ou ceux indiqué par la doc Traefik.
- "GANDIV5_API_KEY=${GANDIV5_API_KEY}"
- OVH_APPLICATION_KEY=${OVH_APPLICATION_KEY}
- OVH_APPLICATION_SECRET=${OVH_APPLICATION_SECRET}
- OVH_CONSUMER_KEY=${OVH_CONSUMER_KEY}

volumes:
- "./dnschallenge:/dnschallenge"
- "/var/run/docker.sock:/var/run/docker.sock:ro"

networks:
- frontend

networks:
frontend:
external: true


Attention ! Deux choses à noter :

Pour gandi, ne touchez pas la ligne suivante :

      - --certificatesresolvers.letsencrypt.acme.dnschallenge.provider=gandiv5

Pour OVH, ou pour un autre registrar, il faudra bien le changer :

        - --certificatesresolvers.letsencrypt.acme.dnschallenge.provider=ovh

C'est parti !

# On lance le conteneur
docker compose up -d
# on check les logs
docker logs -f

Attendez quelques instants que les logs se calment, et allons tester tout ceci avec un conteneur de test.


version: "3"
services:
whoami:
image: "traefik/whoami"
container_name: "simple-service"
labels:
- traefik.enable=true
- traefik.docker.network=frontend
- traefik.http.routers.whoami.tls.certresolver=letsencrypt
- traefik.http.routers.whoami.tls.domains[0].main=${DOMAIN}
- traefik.http.routers.whoami.tls.domains[0].sans=*.${DOMAIN}

- traefik.http.routers.whoami.rule=HostRegexp(`{sub:[a-zA-Z0-9-]+}.${DOMAIN}`) || Host(`${DOMAIN}`)
- traefik.http.routers.whoami.entrypoints=websecure

networks:
- frontend

networks:
frontend:
external: true

Notez la regex sur la règle DNS. Elle permet de matcher tous les sous-domaines de votre domaine. Sexy isn't it ?

Si tout ce passe bien, dans les logs de Traefik, vous devriez voir quelque chose comme ça :

 traefik_wild  | time="2023-11-08T16:40:36Z" level=debug msg="legolog: [INFO] [tibillet.coop] Server responded with a certificate."                                                            traefik_wild  | time="2023-11-08T16:40:36Z" level=debug msg="Certificates obtained for domains [tibillet.coop *.tibillet.coop]" providerName=letsencrypt.acme ACME CA="https://acme-v02.api.le
tsencrypt.org/directory"

Si non, remontez bien les logs, le problème est forcément indiqué dedans.

En production ?

Ahah ! Par ce que vous pensiez que c'était fini ?

Le compose de Traefik contien une petite astuce, nous avons utilisé le serveur de test de Letsencrypt. Pourquoi ? Eh bien le serveur de production qui génère de vrais certificats est soumis à une limite du nombre de demande.

Je l'ai découvert à mes dépens, en voulant tester un peu trop de fois mon système, j'ai dû attendre quelques heures pour pouvoir relancer un nouveau certificat... Le serveur de test nous permet par contre de se planter sans limite. J'adore.

Pour passer en production, lorsque les logs du conteneur traefik vous indiqueront que tout roule, il suffit de commenter la ligne suivante :

#      - --certificatesresolvers.letsencrypt.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory

Et hop, relancer en mode daemon :

docker compose up -d

Enfin, re-lancez le conteneur whoami et vérifier qu'il matche bien. Remplacez bien sur le DNS par le votre, lancez le conteneur, et allez vérifier sur votre navigateur que le certificat est valide pour tout les sous-domaines que vous souhaitez (https://patate.votre_dns , https://prout.votre_dns, etc...)

Si ça coince, rechargez, videz vos certifs auto générés, et enfin regardez les logs Traefik, ce dernier vous signalera forcement le problème dans un message d'erreur.

Sources et liens utiles :

· 4 minutes de lecture
Jonas Turbeaux

/img/federons/decollage.jpg

Nous allons détailler ici la préparation d'un serveur sous distribution Debian (ou Ubuntu) pour acceuillir toutes nos solutions libres que nous proposons dans la coopérative.

Préparation du système

Mises à jour du système

sudo apt update
sudo apt upgrade -y
sudo reboot

Sécuriser le serveur

Connexion SHH par clé

# Depuis votre ordinateur client
ssh-copy-id <user>@<ip>
# ou ajouter votre cle id_rsa.pub directement sur le serveur
nano .ssh/authorized_keys

Changer le port d'écoute du service SSH et obliger la connexion via clé ssh

sudo nano /etc/ssh/sshd_config
# Port 22
Port 2252 # choisissez un port entre 1024 et 65535

# On en profite pour autoriser l'agent forwarding
# Cela sera trés utile pour pull/push des dépots git avec sa propre identité
# plutôt que celle du serveur.
AllowAgentForwarding yes

# Pour encore plus d'efficacité, on force la clé ssh.
# L'user n'en sera que plus reconnaissable, avec sa clé et son agent
# Attention à bien backuper votre clé. Si vous la perdez, vous perdez la main sur le serveur.

# To disable tunneled clear text passwords, change to no here!
PasswordAuthentication no
#PermitEmptyPasswords no


Attention, sur les serveurs VPS Ovh, un fichier de conf' ssh se cache dans le dossier /etc/ssh/sshd_config.d/ et permet la connexion via mot de passe. C'est utile pour la première connexion, mais ^ensez à le supprimer si vous voulez forcer la connexion par clé.

On recharge le daemon ssh :

sudo service sshd reload

Installer Crowdsec

Crowdsec est une solution open source très utile pour gérer la sécurité de votre serveur. Il utilise une liste de banissement d'ip géré par la communauté, surveille les iptables, et peut même s'interfacer avec un reverse proxy pour surveiller les requetes http. Plus d'info ici :

Avant d'installer la solution, il est nécéssaire de créer un compte gratuit sur leur site.

curl -s https://packagecloud.io/install/repositories/crowdsec/crowdsec/script.deb.sh | sudo bash
sudo apt-get install crowdsec
sudo apt install crowdsec-firewall-bouncer-iptables

Allez sur l'interface Crowdsec et générez votre token d'invitation :

Une commande du type suivant vous sera proposé :

sudo cscli console enroll ****

Lancez la, puis accepter l'invitation sur l'interface web.

Rebootez le serveur.

Installation des dépendances

Mes ptits softs que j'aime utiliser :

sudo apt update
sudo apt install git byobu htop borgbackup

Docker :

# Un script d'installation est disponible, si vous ne voulez pas le faire a la main.
curl -fsSL https://get.docker.com -o get-docker.sh
# Attention ! Vérifiez toujours le contenus des scripts téléchargé avant de les lancer en sudo !
sudo sh get-docker.sh
# Ajoutez votre utilisteur au groupe docker
sudo usermod -aG docker $USER

Relancez une nouvelle session utilisateur pour prendre en compte les changements de groupes et vérifiez que vous avez bien les droits :

docker ps

Traefik

Traefik est un service de reverse proxy. C'est lui qui gère la redirection du conteneur depuis votre DNS et qui s'occupe du chiffrement HTTPS grâce à la formidable initiative de lets'encrypt.

Pour le faire tourner, vous devez avoir un nom de domaine qui pointe vers l'ip de votre serveur. Ajoutez un champ A sur votre admin DNS.

#clonez le dépot
git clone git@github.com:TiBillet/Traefik-reverse-proxy.git
cd Traefik-reverse-proxy
# Creez le sous réseau "frontend" commun
docker network create frontend
# Lancez les conteneur en mode daemon
docker compose up -d
# Vérifiez que le conteneur tourne et qu'il écoute bien les ports 80 et 443 :
docker ps
CONTAINER ID   IMAGE               COMMAND                  CREATED         STATUS         PORTS                                                                    NAMES
7f27255b935a traefik:chevrotin "/entrypoint.sh --lo…" 5 seconds ago Up 4 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp traefik

Testons Traefik :

Lançons un conteneur de test pour savoir si tout tourne bien :

cd Traefik-reverse-proxy/test_conteneur
cat "DOMAIN=localhost" > .env # créons un fichier .env qui sera lu par compose
docker compose up

Si vous allez dans https://test.localhost, vous devriez voir une page whoami !

Si vous avez un DNS qui pointe vers l'ip de votre serveur, changez le .env en conséquence pour avoir une connexion chiffrée en TLS !

Conclusion

Et Hop ! Notre serveur est prêt pour acceuillir tous nos services futurs. Dans un prochain article, nous allons voir comment installer Traefik en mode Wildcard pour le moteur TiBillet d'adhésion, de reservation et d'agenda fédéré !