TP 8 : Mise en place du protocole HTTPS#

1. Conception#

1.1. Rappel du fonctionnement du protocole HTTPS#

Indication

L’HyperText Transfer Protocol Secure (HTTPS, littéralement « protocole de transfert hypertextuel sécurisé ») est la combinaison du HTTP avec une couche de chiffrement comme SSL ou TLS.

Source : Wikipédia

L’objectif d’HTTPS est de créer les conditions d’une communication sécurisée sur un réseau non sécurisé. Il garantit l’intégrité et la confidentialité des données transférées entre client et serveur.

Une transaction HTTPS fonctionne en huit étapes :

  1. Le navigateur client et le serveur échangent une paire de messages de type « Hello »,

  2. Chacun communique à l’autre son standard de chiffrement,

  3. Le serveur transmet son certificat au navigateur,

  4. Le client vérifie la validité du certificat du serveur,1

  5. Le client génère une clé secrète,

  6. Cette clé secrète est chiffrée à l’aide de la clé publique du serveur et transmise à ce dernier,

  7. Le client et le serveur confirment qu’ils possèdent la clé secrète (aussi appelée clé de session),

  8. La transmission de données peut commencer, elle est chiffrée de manière symétrique par la clé de session.

1.2. Application à notre infrastructure#

Dans le cas présent, nous n’allons chiffrer les communications qu’en extérieur de notre serveur, car chiffrer les communications sur le réseau interne n’aurait aucun sens : ce réseau étant interne, il est par définition sécurisé, y ajouter une couche de sécurité supplémentaire ne ferait qu’alourdir les communications pour un gain nul sur le plan de la sécurité. Les communications sur notre infrastructure seront donc organisées ainsi :

Ce processus nécessite donc la création de deux éléments de sécurité du côté du serveur :

  • Un certificat approuvé par une autorité de confiance couvrant nos deux noms de domaines,

  • Une paire de clés asymétriques, l’une privée et l’autre publique.

L’autorité de confiance que nous utiliserons cette fois–ci sera Let’s Encrypt (LE). Créée en décembre 2015 pour aider à démocratiser l’accès aux certificats HTTPS, cette organisation à but non lucratif s’est fixée un objectif simple : rendre la création de certificat possible en deux commandes ou moins.

Pour automatiser la création d’un certificat, Let’s Encrypt a créé un protocole appelé Automated Certificate Management Environment ou ACME, qui consiste à monter un serveur TLS spécifique temporairement sur le serveur hôte, puis à tenter de communiquer avec lui depuis le serveur de l’autorité de certification, ceci afin de vérifier que le domaine redirige bien sur le serveur qui demande le certificat.

Cette méthode, pourtant bien pratique, ne pourra être utilisée ici : pour la mettre en œuvre, ACME a besoin de prendre la main sur le serveur de reverse-proxy de l’hôte. Notre nginx étant dans un conteneur, cette opération n’est pas possible simplement. Nous devrons donc effectuer la création des certificats manuellement.

2. Mise en œuvre#

2.1. Création du certificat#

Heureusement pour nous, Let’s Encrypt a intégré d’autres systèmes de vérification dans son outil en ligne de commande (Certbot), notamment un mode manuel qui nous simplifiera largement la tâche par rapport à une création conventionnelle de certificats.

Nous exécuterons donc la commande suivante :

docker run -it \
  --rm \  # Le conteneur est automatiquement supprimé dès que la tâche est terminée
  --name ct \
  -v /opt/certbot/letsencrypt:/etc/letsencrypt \
  certbot/certbot:v1.8.0 \
  certonly \                            # Commande passée à certbot
    --manual \                          # Mode manuel
    --preferred-challenges=dns \        # Type de vérification (ici enregistrement dns)
    --email contact@enseirb.net \       # Email de contact
    --server https://acme-v02.api.letsencrypt.org/directory \  # Serveur ACME
    --agree-tos \                       # Acceptation des CGU
    -d <id-personnel>.enseirb.net \     # Domaine 1
    -d back.<id-personnel>.enseirb.net  # Domaine 2
# Version pour copier/coller
docker run -it --rm --name ct -v /opt/certbot/letsencrypt:/etc/letsencrypt certbot/certbot:v1.8.0 certonly --manual --preferred-challenges=dns --email contact@enseirb.net --server https://acme-v02.api.letsencrypt.org/directory --agree-tos -d <id-personnel>.enseirb.net -d back.<id-personnel>.enseirb.net

Après une rapide initialisation, certbot va vous afficher quelque chose qui ressemble à ceci :

Please deploy a DNS TXT record under the name:

_acme-challenge.back.<id-personnel>.enseirb.net.

with the following value:

<un-très-long-hash>

À ce stade, ne SURTOUT PAS APPUYER SUR ENTRÉE !

Avant de valider le challenge, il va falloir créer un enregistrement DNS de type TXT qui contienne le hash fourni par certbot. Transmettez le code à l’enseignant, qui se chargera de créer l’enregistrement pour vous (n’hésitez pas à regarder comment il s’y prend).2

Une fois l’opération effectuée, appuyez sur ENTRÉE pour lancer le processus de vérification. Le processus en entier est à effectuer deux fois, une fois par domaine.

À l’issue de cette procédure, vous trouverez votre certificat sous /opt/certbot/letsencrypt/archive/<id-personnel>.enseirb.net3 L’accès est restreint à root uniquement, aussi il vous faudra exécuter la procédure suivante :

sudo cp -r /opt/certbot/letsencrypt/archive/<id-personnel>.enseirb.net ~/grp/certificates/<id-personnel>.enseirb.net
sudo chown -R $(whoami):$(whoami) certificates
sudo chmod -R 0600 certificates

Note

Si vous faites un sudo ls ~/certificates/<id-personnel>.enseirb.net, vous remarquerez qu’il y a quatre fichiers. Seuls deux nous intéressent ici : fullchain1.pem qui contient le certificat et la clé publique, et privkey1.pem qui contient la clé privée.

2.2. Modification des configurations nginx#

Les configurations nginx vont subir des modifications pour le moins massives. Le cahier des charges est le suivant :

Nginx doit écouter sur les ports 80 (HTTP) et 443 (HTTPS)

  • S’il reçoit une requête sur le port 80, il vérifie que le domaine est le bon

    • Si oui, il la redirige vers le port 443 avec un code 301 (Moved Permanently)

    • Sinon, il retourne une erreur 404

  • S’il reçoit une requête sur le port 443, il met une place une communication HTTPS à l’aide du certificat et des clés, puis redirige la requête sur le bon service interne.

Cela se traduit ainsi pour une configuration <id-personnel>.enseirb.conf :

server {
  listen 80;
  listen [::]:80;
  server_name <id-personnel>.enseirb.net;
  
  if ($host = <id-personnel>.enseirb.net) {
    return 301 https://$host$request_uri;
  }
  
  return 404;
}

server {
  listen 443 ssl;  # Le mot-clé `ssl` appelle nginx à attendre des communications HTTPS
  listen [::]:443 ssl;
  server_name <id-personnel>.enseirb.net;
  
  location / {
    proxy_pass http://front;
  }
  
  ssl_certificate /opt/certificates/<id-personnel>.enseirb.net/fullchain1.pem;
  ssl_certificate_key /opt/certificates/<id-personnel>.enseirb.net/privkey1.pem;
}

Ainsi, nginx saura quoi faire en toute situation. Modifiez vos deux configurations en vous basant sur cet exemple. Les deux configurations se basent sur le même certificat.

2.3. Modification de la configuration Docker Compose#

Premièrement, il nous faut ouvrir le port 443 à l’extérieur au niveau du firewall :

sudo ufw allow 443

Puis, il faut créer une redirection de ports entre le port 443 de l’hôte et celui du conteneur, et monter les certificats dans le filesystem du conteneur.

  nginx:
    image: nginx:stable-alpine
    networks:
      - net
    volumes:
      - ./nginx/:/etc/nginx/conf.d/
      - ./certificates/:/opt/certificates/
    ports:
      - "80:80"
      - "443:443"

Et enfin, mettre à jour toute l’infrastructure via la commande docker compose up -d, avant de tester le résultat en visitant https://<id-personnel>.enseirb.net.


1

Pour ce faire, le client va vérifier que le certificat a été approuvé par une autorité de confiance, c’est-à-dire une autorité de certification qu’il connaît déjà.

2

D’ici au prochain cours, je vais essayer de vous monter une petite interface pour que vous puissiez gérer vous-même votre zone DNS.

3

Le répertoire couramment utilisé est /etc/letsencrypt/live/<domain>, mais ce dernier contient des liens symboliques vers les certificats contenus dans /etc/letsencrypt/archive/<domain>. On veut ici les fichiers source.