Sécuriser ses sites avec letsencrypt et acme-tiny

De Linux Server Wiki
Aller à la navigation Aller à la recherche

Les tutos Installation et configuration d'un serveur http apache 2.2 ainsi que Installation et configuration de OpenSSL vous expliquent comment générer des certificats auto-signés et configurer vos vhosts Apache.

Ceci dit les certificats auto-signés présentent un inconvénient majeur : ils génèrent des alertes de sécurité dans les navigateurs.

Ils conviennent donc tout à fait pour sécuriser une interface d'admin, mais dès lors où votre site est ouvert au "public" ils ne sont plus utilisables, les messages d'alertes dans les navigateurs étant plus que dissuasifs.

Depuis peu une nouvelle autorité de certification a vu le jour : https://letsencrypt.org/

Cette autorité vise à fournir gratuitement des certificats de sécurité reconnus dans les navigateurs (grâce dès aujourd'hui à une signature croisée avec une autre autorité)

Il n'y a donc plus d'excuses pour ne pas proposer de HTTPS sur vos sites !

Pourquoi acme-tiny ?

Letsencrypt propose un client officiel qui se charge de presque tout pour vous mais qui a plusieurs défauts, entre autre le fait que vous n'avez pas vraiment la main sur son fonctionnement, qu'il nécessite pas mal de dépendances, doit tourner en root, etc.

Letsencrypt étant un projet OpenSource, il existe de nombreux autres scripts proposant plus ou moins de fonctionnalités, acme-tiny en fait parti : https://github.com/diafygi/acme-tiny

Ce script vous permet de générer le certificat en passant par letsencrypt tout en gardant la main sur votre config Apache, la façon dont vous gérez les certificats, etc.

Pré-configuration (pour la première utilisation)

Avant de générer les certificats, commencez par créer un utilisateur dédié qui se chargera de faire tourner le script. Nous partirons sur un utilisateur nommé acme, avec un home dans /home/acme.

Avec cet utilisateur (su - acme) :

cd /home/acme
mkdir work secrets
chmod 750 work
chmod 700 secrets
git clone https://github.com/diafygi/acme-tiny.git
chmod +x acme-tiny/acme_tiny.py

Le répertoire secrets servira à héberger les clés (fichiers .key), le work hébergera les différents fichiers des certifiats (crt, csr, pem).

On restreint les droits sur les dossiers et enfin on récupère le script et on le rend exécutable.

Génération des clés

Afin de communiquer avec letsencrypt il vous faut un fichier de clé qui vous authentifie auprès d'eux. Ce fichier est extrêmement important (pensez à bien le sauvegarder) et bien sûr totalement privé.

Si vous n'en avez pas encore vous pouvez le générer de la façon suivante :

openssl genrsa 4096 > /home/acme/secrets/account.key
chmod 600 /home/acme/secrets/account.key

Ce fichier de clé est réutilisable sur tous vos domaines.

Ensuite il vous faudra un fichier de clé par domaine que vous voulez sécuriser, même principe :

openssl genrsa 4096 > /home/acme/secrets/networklab.fr.key
chmod 600 /home/acme/secrets/networklab.fr.key
mkdir /home/acme/work/networklab.fr
chmod -R 750 /home/acme/work/

Ici pour le domaine networklab.fr, à adapter dans votre cas. On créé également un répertoire dédié au domaine dans work.

Configuration pour la demande du certificat

Afin de demander votre certificat il est nécessaire de générer une demande de certificat. Si vous n'avez qu'une adresse qui sera derrière votre certificat :

openssl req -new -sha256 -key /home/acme/secrets/networklab.fr.key -subj "/CN=networklab.fr" -out /home/acme/work/networklab.fr/networklab.fr.csr

Mais plus généralement vous en aurez au moins deux (une avec et une sans le www) :

openssl req -new -sha256 -key /home/acme/secrets/networklab.fr.key -subj "/" -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf "[SAN]\nsubjectAltName=DNS:networklab.fr,DNS:www.networklab.fr")) -out /home/acme/work/networklab.fr/networklab.fr.csr

Vous pouvez vérifier les différentes informations entrés dans le CSR avec la commande suivante :

openssl req -in /home/acme/work/networklab.fr/networklab.fr.csr -noout -text

Avant de générer votre certificat, letsencrypt vient vérifier que votre site vous appartient bien. Pour cela le script va déposer un fichier de "challenge" à l'endroit que vous lui définissez et qui doit être accessible à l'adresse /.well-known/acme-challenge/.

Pour cela il faut donc que votre utilisateur acme puisse écrire dans un dossier de votre site.

Ici nous partons du principe que vous avez un couple d'utilisateur/groupe par site que vous hébergez. Si vous avez une configuration d'Apache avec un seul utilisateur ça n'en sera que plus simple.

En root :

usermod -a -G networklab.fr acme

On ajoute le groupe networklab.fr en groupe secondaire de l'utilisateur acme.

Avec l'utilisateur correspondant à votre site (pour nous networklab.fr) :

cd /home/networklab.fr/www/
mkdir challenges
chmod g+w challenges/

Le dossier challenges hébergera le fichier de challenge que letsencrypt va vérifier. On donne le droit d'écriture au groupe pour que l'utilisateur acme puisse y écrire.

Enfin en root dans la configuration Apache de votre site il faudra ajouter :

<Directory "/home/networklab.fr/www/challenges">
    AllowOverride None
    Require all granted
    Order allow,deny
    Allow from all
   </Directory>
Alias /.well-known/acme-challenge "/home/networklab.fr/www/challenges"

Pensez à bien reload Apache après cette modification.

Attention : letsencrypt viendra chercher le fichier de challenge en HTTP et non en HTTPS. Si vous redirigez automatiquement en HTTPS pensez à mettre une exception sur cette adresse.

De même si vous sécurisez un domaine "d'administration" avec ne protection par .htpasswd pensez également à mettre une exception.

Pour cela ajoutez dans le .htaccess :

SetEnvIf Request_URI "(challenges/)$" allow
SetEnvIf Request_URI "(\.well-known/acme-challenge/)$" allow

Génération du certificat

De retour en utilisateur acme, voici le script vous permettant de générer votre certificat :

#! /bin/bash
umask 022
python /home/acme/acme-tiny/acme_tiny.py --account-key /home/acme/secrets/account.key --csr /home/acme/work/networklab.fr/networklab.fr.csr --acme-dir /home/networklab.fr/www/challenges/ > /home/acme/work/networklab.fr/networklab.fr.crt
umask 027
wget -O /home/acme/work/networklab.fr/intermediate.pem https://letsencrypt.org/certs/lets-encrypt-x1-cross-signed.pem
cat /home/acme/work/networklab.fr/networklab.fr.crt /home/acme/work/networklab.fr/intermediate.pem  > /home/acme/work/networklab.fr/networklab.fr.pem

Le changement d'umask permet d'écrire le fichier de challenges avec des droits permettant à Apache de servir le fichier (le fichier étant créé en acme:acme, l'umask 027 ne le permet pas). On lance ensuite le script acme-tiny qui prend en paramètres :

  • la clé de votre compte
  • le csr (demande de certificat)
  • l'emplacement où il doit écrire le fichier de challenge

Et en sortie on récupère le certificat.

On repasse ensuite en umask 027, on récupère le certificat intermédiaire de letsencrypt.

Enfin on combine notre certificat au certificat intermédiaire.

Le script est exactement le même pour un renouvellement de certificat. Vous pouvez donc l'enregistrer (dans notre cas /home/acme/networklab.fr.sh).

Configurez ensuite une tâche cron pour renouveler régulièrement votre certificat.

Actuellement les certificats letsencrypt sont valables 90 jours.

Vous pouvez par exemple partir sur une génération mensuelle :

0 4 21 * * /home/acme/networklab.fr.sh

Tous les 21 du mois à 4H00.

Configuration de la vhost et reload d'Apache

Dernière étape en root, il est nécessaire de configurer votre vhost en HTTPS. Si vous n'aviez que du HTTP vous pouvez rajouter :

<VirtualHost *:443>
        SSLEngine on
        SSLCertificateChainFile /home/acme/work/networklab.fr/intermediate.pem
        SSLCertificateFile /home/acme/work/networklab.fr/networklab.fr.pem
        SSLCertificateKeyFile /home/acme/secrets/networklab.fr.key
        SSLProtocol all -SSLv2 -SSLv3 -TLSv1
        SSLCipherSuite ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK
        SSLHonorCipherOrder on
        Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains"
        Header always set X-Frame-Options DENY
        ServerName networklab.fr
        ServerAlias www.networklab.fr
        Include /etc/apache2/sites-config/networklab.fr.conf
</VirtualHost>

On retrouve la configuration du certificat intermédiaire, du certificat de notre domaine et de la clé. Ensuite différentes configurations SSL, à adapter selon la date à laquelle vous lirez ce tuto.

Dernière étape, configurer un reload d'Apache juste après la date prévue pour le renouvellement de vos certificats. Vous pouvez au choix :

  • donner le droit à l'utilisateur acme de reload Apache et le rajouter à votre script
  • faire un cron en root à une date/heure définie juste après tous vos scripts de renouvellement

Ici nous utiliserons le cron en root :

5 4 21 * * /etc/init.d/apache2 reload

Tous les 21 du mois à 4H05.

Et voilà, vous aurez dorénavant un site en HTTPS avec renouvellement automatique du certificat. Vous pouvez facilement reproduire la chose pour d'autres domaines en refaisant les étapes 3 à 6. Pensez à surveiller que vos certificats se renouvellent bien (idéalement avec du monitoring qui vous alertera en cas de soucis !)