Créer et installer un certificat SSL Let’s Encrypt pour Apache

A propos de Let’s Encrypt

Let’s encrypt est une initiative Open Source de l’ISRG qui a pour objectifs résumés de proposer à tous, gratuitement, des certificats SSL permettant de sécuriser un site web via https.
Il faut bien avouer que Let’s Encrypt est la petite révolution, tout le monde s’y met. Et ce pour 2 raisons principales : Le fait que ce soit simple ET gratuit, et surtout depuis que Google pousse pour un web sécurisé.

Nous allons donc voir comment déployer Let’s Encrypt sur notre serveur Apache, mais d’une façon particulière.
En effet, le logiciel Certbot que nous allons utiliser propose divers plugins et assistants, dont pour Apache, qui permettent d’installer automatiquement les certificats, de modifier les configurations d’Apache, etc… Tout cela automatiquement.
Cela conviendra parfaitement au plus grand nombre, il faut bien le dire.
Mais personnellement, j’aime bien : 1/ savoir ce qu’il se passe, 2/ savoir comment cela fonctionne, 3/ garder la main sur le paramétrage.

En le faisant manuellement, au moins, en cas de problème, je sais où chercher et où intervenir.

Pour ce tuto je pars du principe que nous avons une configuration Apache classique, et qu’il n’y pas de cas particuliers.
Je suppose aussi que nous avons plusieurs sites hébergés sur notre serveur et qu’un ou plusieurs d’entre eux vont passer du http au https.

Enfin, notez que ce tutoriel est réalisé sur une Debian 8 et Apache 2.4.

Prérequis

Avoir installé un serveur Apache 2 et qu’il soit fonctionnel avec les mods SSL et rewrite activés.
Pour vérifier s’ils sont actifs exécutez :

root@g:~# apache2ctl -M
Loaded Modules:
 ...
 rewrite_module (shared)
 ssl_module (shared)
 ...
Syntax OK

Vous voyez en gras les 2 modules chargés.
Si ce n’est pas le cas, exécutez en fonction :

root@g:~# a2enmod ssl 
Enabling module ssl.
See /usr/share/doc/apache2.2-common/README.Debian.gz on how to configure SSL and create self-signed certificates.
To activate the new configuration, you need to run:
  service apache2 restart

root@g:~# a2enmod rewrite 
Enabling module rewrite.
To activate the new configuration, you need to run:
  service apache2 restart

root@g:~# /etc/init.d/apache2 restart 
[ ok ] Restarting web server: apache2 ... waiting .

N’oubliez pas de redémarrer Apache une fois que les modules sont mis à jour.


Méthodologie

La mise en place va se faire en 6 grandes étapes :

  1. Installer le programme Certbot qui va générer les certificats
  2. Créer un premier certificat Let’s Encrypt
  3. Modifier la configuration d’un vhost Apache pour y intégrer les certificats
  4. Vérifier la configuration ainsi que la qualité du paramétrage SSL
  5. Apprendre à renouveler un certificat
  6. Apprendre à révoquer un certificat

Installation de Certbot

Pour commencer, on télécharge Certbot et on le rend exécutable :

wget https://dl.eff.org/certbot
chmod a+x certbot

C’est un simple fichier, stockez le à un endroit approprié. Dans /opt par exemple.
Exécutez-le une première fois « à blanc » pour qu’il télécharge ses dépendances et s’installe.

./certbot

Lorsque ce sera terminé, il vous proposera de commencer le travail de création. Quittez.

Les fichiers principaux sont installés. Tout se trouve dans /etc/letsencrypt.
Dans se dossier on trouvera 3 dossiers de stockage pour les certificats :
archive : dossier de base ou sont stockés les certificats
live : dossier des certificats actifs. Des liens symboliques vers le dossier archive.
renewal : dossier qui contient les informations de renouvellement des certificats.

Création du certificat Let’s Encrypt

Lancez la commande suivante en veillant à remplacer les valeurs par les bonnes informations :

./certbot certonly --webroot --webroot-path /srv/www/Nom_repertoire/ --domain nom_domain.tld --domain www.nom_domain.tld --email Cette adresse e-mail est protégée contre les robots spammeurs. Vous devez activer le JavaScript pour la visualiser.

Exemple: 

./certbot certonly --webroot --webroot-path /var/www/html/linux/ --domain linux.decalog.net --email Cette adresse e-mail est protégée contre les robots spammeurs. Vous devez activer le JavaScript pour la visualiser.

info: commande cerbot ou cerbot-auto en fonctionne de la verssion

Explications :

certonly : on demande la création du certificat uniquement.
--webroot : on utilise le plugin webroot qui se contente d’ajouter des fichiers dans le dossier défini via --webroot-path.
--webroot-path : le chemin de votre « DocumentRoot » Apache (répertoire de votre site). Certbot placera ses fichiers dans $DocumentRoot/.well-known/ pour les tests et vérifications
--domain : le nom de domaine à certifier.
--email : l’adresse qui recevra les notifications de Let’s Encrypt. Principalement pour rappeler de renouveler le certificat le moment venu.

Options de création

Au niveau des paramètres de création, l’essentiel est là. Je vous invite à consulter la doc pour voir les autres options disponibles.
On pourrait éventuellement durcir le certificat en le passant en 4096 bits (2048 bits par défaut) en ajoutant le flag --rsa-key-size 4096 mais c’est un peu disproportionné. C’est vous qui voyez.

Pour revenir sur le flag --domain, attention ! Let’s encrypt ne gère pas à ce jour le Wildcard. Il faut donc penser impérativement à déclarer le domaine ET le sous-domaine « www ». Si vous êtes dans une configuration classique évidemment où votre site est accessible depuis http://domain.tld et http://www.domain.tld.

Les certificats obtenus

Si vous cherchez vos certificats, ils se trouvent dans les dossiers : /etc/letsencrypt/live/domain.tld/
Vous avez pour chaque certificat 4 fichiers :

privkey.pem : La clé privée de votre certificat. A garder confidentielle en toutes circonstances et à ne communiquer à personne quel que soit le prétexte. Vous êtes prévenus !
cert.pem : Le certificat serveur et à préciser pour les versions d’Apache < 2.4.8. Ce qui est notre cas ici.
chain.pem : Les autres certificats, SAUF le certificat serveur. Par exemple les certificats intermédiaires. Là encore pour les versions d’Apache < 2.4.8.
fullchain.pem : Logiquement, l’ensemble des certificats. La concaténation du cert.pem et du chain.pem. A utiliser cette fois-ci pour les versions d’Apache >= 2.4.8.

Le cas des certificats pour différents sous-domaines

Pour une gestion simplifiée de vos certificats, je vous conseille de ne pas intégrer tous vos sous-domaines au même certificat.
Si vous gérez plusieurs sites différents sur des sous-domaines différents, et donc sur des vhost différents : par exemple blog.domain.com et forum.domain.com, à ce moment là vous créer 2 certificats distincts. Comme cela, en cas de modification, déplacement ou suppression de l’un de vos sites, tout est cloisonné et il n’y a pas d’impacts sur les autres certificats.

Intégrer le certificat Let’s Encrypt à Apache

Maintenant que nous avons le certificat, il ne reste plus qu’à l’intégrer au vhost Apache et ainsi servir du contenu en https.
Tout d’abord il faut éditer le vhost afin de déclarer tout le paramétrage nécessaire.
Je suppose ici que nous sommes dans un cas classique où notre site est accessible à la fois depuis domain.com et www.domain.com. Le grand classique.

Modification du vhost

Pour l’instant le vhost ressemble à quelque chose comme ceci :

<VirtualHost *:80>

    ServerName domain.tld
    ServerAlias www.domain.tld
    DocumentRoot /path/to/files

    LogLevel warn
    ErrorLog ${APACHE_LOG_DIR}/domain.tld-error.log
    CustomLog ${APACHE_LOG_DIR}/domain.tld-access.log combined

    RewriteEngine On
    RewriteCond %{HTTP_HOST} !^www\. [NC]
    RewriteRule ^(.*)$ http://www.%{HTTP_HOST}$1 [R=301,L]

    <Directory /path/to/files>
        Options -Indexes -MultiViews
        AllowOverride all
        Order allow,deny
        allow from all
    </Directory>

</VirtualHost>

Ici, le détail de cette configuration importe peu. L’important est de voir que le site est accessible à la fois depuis domain.tld et www.domain.tld, et que si quelqu’un demande http://domain.tld : il y aura une redirection 301 automatique vers le sous-domaine http://www.domain.tld.

Nous allons reproduire la même chose en version https. Je vous propose la nouvelle configuration suivante :

<VirtualHost *:80>

    ServerName domain.tld
    ServerAlias www.domain.tld

    RewriteEngine on
    RewriteCond %{HTTPS} !on
    RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}

</VirtualHost>

<VirtualHost *:443>

    ServerName domain.tld
    ServerAlias www.domain.tld

    DocumentRoot /path/to/files/www.domain.tld

    <Directory /path/to/files>
        Options -Indexes
        AllowOverride all
        Order allow,deny
        allow from all
    </Directory>

    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/domain.tld/cert.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/domain.tld/privkey.pem
    SSLCertificateChainFile /etc/letsencrypt/live/domain.tld/chain.pem
    SSLProtocol all -SSLv2 -SSLv3
    SSLHonorCipherOrder on
    SSLCompression off
    SSLOptions +StrictRequire
    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:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"

    LogLevel warn
    ErrorLog ${APACHE_LOG_DIR}/www.domain.tld-error.log
    CustomLog ${APACHE_LOG_DIR}/www.domain.tld-access.log combined

</VirtualHost>

 

On voit maintenant que l’on a 2 vhost dans un vhost ! Un pour le port 80 et le http (<VirtualHost *:80>) et un autre pour le port 443 et le https (<VirtualHost *:443>).
Le premier vhost du port 80 ne fait rien d’autre qu’une redirection automatique de l’http vers le https. SI jamais quelqu’un le demandait.
Mis à part cela, il n’y a rien. Pas de documentRoot, pas de logs, etc… C’est un choix. Etant donné que je souhaite que 100% du trafic passe sur https, toutes les informations complémentaires sont inutiles, à commencer pour les logs.

Ensuite il y a la déclaration du vhost https. Comme vous pouvez le voir, la première partie est identique à la configuration initiale, et il n’y a pas de raison qu’elle soit différente. Par contre, en deuxième partie, il y a toutes les déclarations SSL :

SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/domain.tld/cert.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/domain.tld/privkey.pem
    SSLCertificateChainFile /etc/letsencrypt/live/domain.tld/chain.pem
    SSLProtocol all -SSLv2 -SSLv3
    SSLHonorCipherOrder on
    SSLCompression off
    SSLOptions +StrictRequire
    SSLCipherSuite ECDHE-RSA-AES128-GCM-SHA256 [...]
    # Note: It’s also recommended to enable HTTP Strict Transport Security (HSTS)
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"

 

Explications :

SSLEngine on : Activation du module SSL
SSLCertificateFile : chemin vers le fichier cert.pem
SSLCertificateKeyFile : chemin vers le fichier privkey.pem
SSLCertificateChainFile : chemin vers le fichier chain.pem
SSLProtocol : Active le support de toutes les versions SSL mais SAUF SSLv2 et v3 qui ne sont plus suffisamment sécurisées.
SSLHonorCipherOrder : Quand activé, le serveur force ses préférences de protocoles et non le navigateur du client.
SSLCompression : Active la compression SSL
SSLOptions +StrictRequire : Exige une connexion SSL stricte
SSLCipherSuite : Liste des algorithmes de chiffrement disponibles
Header always set Strict-Transport-Security : ou HSTS. Indique aux navigateurs que seul le https est supporté et le force en définissant une durée d’application (longue). Objectif : éviter les attaques « Man in the middle ».

Vérification de la configuration du vhost

Reste maintenant à tester notre configuration :

apache2ctl -t

Logiquement devrait vous retourner un « Syntax OK ». Si c’est le cas, il faut reload/restart Apache pour qu’il prenne en compte les modifications.

/etc/init.d/apache2 restart

Et là, vous pouvez avoir l’erreur suivante :

[....] Reloading web server config: apache2[Sat Oct 08 11:17:49 2016] [warn] _default_ VirtualHost overlap on port 443, the first has precedence.
... waiting [Sat Oct 08 11:17:49 2016] [warn] _default_ VirtualHost overlap on port 443, the first has precedence
ok

Nous venons d’ajouter un nouveau vhost écoutant sur le port 443 mais nous avons aussi le vhost « default-ssl » qui est déjà présent. Donc 2 vhost, 2 sites pour le même port ça ne va pas. Il faut donner des précisions à Apache pour qu’il sache quoi servir.
Etant dans un contexte de serveurs basés sur le nom, il faut ajouter cette instruction au fichier ports.conf, qui ressemble à ceci par défaut :

<IfModule mod_ssl.c>
    # If you add NameVirtualHost *:443 here, you will also have to change
    # the VirtualHost statement in /etc/apache2/sites-available/default-ssl
    # to <VirtualHost *:443>
    # Server Name Indication for SSL named virtual hosts is currently not
    # supported by MSIE on Windows XP.
    Listen 443
</IfModule>

 

On va lui ajouter l’instruction NameVirtualHost *:443 ce qui nous donnera :

<IfModule mod_ssl.c>
    # If you add NameVirtualHost *:443 here, you will also have to change
    # the VirtualHost statement in /etc/apache2/sites-available/default-ssl
    # to <VirtualHost *:443>
    # Server Name Indication for SSL named virtual hosts is currently not
    # supported by MSIE on Windows XP.
    Listen 443
    NameVirtualHost *:443
</IfModule>

 

Vous noterez que les choses sont biens faites, regardez les commentaires, on nous indique que si on ajoute NameVirtualHost *:443 ici il faut également modifier le vhost default-ssl pour remplacer <VirtualHost _default_:443> par <VirtualHost *:443>.

On édite le fichier /etc/apache2/sites-available/default-ssl sur les 2 premières lignes qui sont :

IfModule mod_ssl.c>
<VirtualHost _default_:443>
...

Et qui deviennent alors :

IfModule mod_ssl.c>
<VirtualHost *:443>
...

On restart Apache une dernière fois et il ne devrait plus y avoir de soucis. Rendez-vous sur votre site, et vous pourrez vérifier que tout fonctionne bien avec https activé et fonctionnel. Et surtout sans alerte.

Vérification de la sécurité

Dernier point à voir sur la configuration : la qualité de sécurisation de notre connexion SSL.
En effet, en fonction des paramètres définis dans notre vhost, entre autre, il se peut que la sécurisation ne soit pas optimale. Il y a donc potentiellement un risque d’usurpation d’identité ou encore d’attaque de type « Man in the middle ».
Avec les paramètres définis plus haut, il n’y a pas de soucis. Vous devriez obtenir la note « A+ ». Il s’agit des paramètres par défaut de Let’s Encrypt. Mais cette note n’est pas sans contrepartie.

Commencez par tester votre site sur SSL Server Test : https://www.ssllabs.com/ssltest/

Si vous avez bien suivi ce tuto, vous devriez avoir le fameux « A+ » :

Maintenant tout est affaire de compromis.
Plus vous durcirez vos règles, plus vous obtiendrez une meilleure note, plus vous perdrez en compatibilité avec les anciens navigateurs. IE8 sur XP par exemple.
Donc regardez bien vos stats de visites au préalable pour connaitre les configurations de vos visiteurs et adaptez en fonction.
La sécurité c’est bien, mais si vous perdez vos visiteurs ce n’est pas une solution non plus.


Renouveler un certificat Let’s Encrypt

A ce stade nous avons un certificat Let’s Encrypt installé et notre serveur bien configuré.
Il faut savoir que la durée de vie du certificat Let’s Encrypt n’est que de 90 jours, 3 mois donc.
Nous allons voir les commandes pour le renouveler manuellement et automatiquement.

Pour renouveler votre certificat manuellement il suffit de lancer la commande :

./certbot renew

Cette commande interroge les serveurs Let’s encrypt et ces derniers vont déterminer si votre certificat a besoin d’être renouvelé ou non.
Notez que tant que vous ne serez pas dans les 30 derniers jours avant la date d’expiration, Let’s encrypt ne le renouvellera pas. Mais si besoin vous pouvez forcer malgré tout le renouvellement en ajoutant le flag --force-renewal.
Lors du renouvellement vous pouvez également demander la modification de la force de la clé RSA. Si vous avez créé votre certificat en 2048 bits, vous pouvez le passer en 4096, et inversement. Pour cela vous ajouterez le flag --rsa-key-size 4096.
La commande serait alors :

./certbot renew --rsa-key-size 4096 --force-renewal

Ce sont là les options principales. Il y en a d’autres disponibles en fonction de vos besoins, là encore je vous invite à consulter la documentation.

Pour terminer sur le renouvellement il est important de signaler que la commande ./certbot renew renouvelle l’ensemble des certificats Let’s Encrypt disponibles sur la machine.
Pour le moment il n’est pas possible de renouveler un domaine en particulier. Cela sera probablement disponible dans le futur.

Renouveler automatiquement le certificat

Maintenant nous allons voir comment automatiser le renouvellement de notre certificat avec CRON.
Personnellement je me créé un petit script que je vais placer dans le dossier cron.monthly. Basique. Et « monthly » car comme vu précédemment le certificat ne sera renouvelé que dans les 30 derniers jours. Inutile donc de faire la demande toutes les semaines et encore moins tous les jours.
Exemple de fichier renew-certificate.sh :

#!/bin/bash

/chemin/vers/certbot renew

Vous pouvez ajouter le flag --quiet si vous ne souhaitez pas avoir de retour sur la commande.
Dans tous les cas, pas de panique, comme nous avons ajouté notre adresse mail lors de la création du certificat, s’il y a le moindre problème, vous serez prévenu par email.

 

Révoquer un certificat Let’s Encrypt

Nous allons utiliser la commande certbot-auto revoke en lui passant un certain nombre de paramètres : le certificat à révoquer, le chemin vers la clé privée et le chemin vers le certificat :

./certbot-auto revoke --domain domain.tld --cert-path /etc/letsencrypt/live/domain.tld --key-path /etc/letsencrypt/live/domain.tld

otre certificat est révoqué. Mais ce n’est pas suffisant.
Si vous regardez vos dossiers /etc/letsencrypt/live/, /archive/ et /renewal/, vous trouverez encore les dossiers/fichiers à l’intérieur.
Pour faire propre, nous allons tout supprimer avec la commande suivante :

rm -rf /etc/letsencrypt/live/domain.tld/ && rm -rf /etc/letsencrypt/archive/domain.tld/ && rm /etc/letsencrypt/renewal/domain.tld.conf

Restaurer la configuration Apache

Dernière modification, restaurer la configuration du vhost Apache dans sa configuration initiale et surtout supprimer toutes les références au SSL et aux certificats.
Pour celaiIl suffit de se référer à la configuration de base plus haut dans cette page. Je vous laisse faire.