Ceci est une ancienne révision du document !
Table des matières
< retour à la page de l'administration technique
Cette page décrit la mise en place des certificats signés par Let's Encrypt sur les serveurs de FedeRez.
Mise en place de Let's Encrypt sur les serveurs FedeRez
Historique
En janvier 2016, la méthode officiellement recommandée pour installer Let's Encrypt consistait à cloner le dépôt officiel de letsencrypt et d'utiliser le script officiel letsencrypt-auto
.
En mai 2016, suite à la disponibilité de paquets officiels dans les Backports de Jessie pour le client officiel Let's Encrypt renommé en certbot
, il a été décidé de migrer sur la version packagée et en même temps de passer du plugin d'auth apache au plugin d'auth webroot.
Fin juin 2016 le cronjob livré avec certbot a été désactivé via dpkg-divert en faveur de notre script personnalisé de renouvellement.
Remarque sur le choix du client certbot
Il existe aussi d'autres clients ACME 1) que le client officiel, qui avancent certains avantages tels que la possibilité de ne pas être exécutés en root, ou bien le fait qu'ils sont fait de peu de lignes de codes et donc plus faciles à auditer.
Après avoir pris en compte tout ceci, il fut décidé de s'en tenir pour le moment au client officiel, avec pour but de migrer vers une alternative plus adaptée une fois que la poussière sera retombée et qu'une meilleure alternative stable et viable se présentera.
Vue d'ensemble du système
Pour le moment, chaque serveur est responsable de générer et faire signer les certificats pour les noms de domaines qu'il gère.
- Le paquet
certbot
a été installé depuis les backports de jessie (jessie-backports). - La configuration et les certificats sont dans
/etc/letsencrypt
:- Le fichier de config utilisé est à créer sous
/etc/letsencrypt/cli.ini
(cf. installation ci-dessous) - La gestion des certificats (requête, validation, récup du certif signé) est faite automatiquement par le client. Voir la documentation officielle pour plus d'informations.
- Au final la seule chose à retenir c'est que les certificats valides se situent sous
/etc/letsencrypt/live/example.org/*
- Le script de renouvellement automatique adapté à FedeRez et au serveur se trouve dans
/root/scripts/renew_letsencrypt_certificates.sh
. C'est ce script qui est appelé dans le crontab chaque jour. C'est ici qu'il faut ajouter les sous-domaines pour lesquels obtenir un certificat. - Le fichier crontab ce situe dans
/etc/cron.d/renew_letsencrypt_certificates_federez
. Note: Le fichier crontab par défaut du paquet certbot a été désactivé via dpkg-divert (Cf. ci-dessous). - Un script de monitoring des certificats SSL est en place pour vérifier la durée de validité restante et alerter si le certificat s'approche de son expiration : voir ssl-cert-check.
Pour le moment, il faut absolument éviter de retirer un sous-domaine de la liste des domaines après que le certificat ait été déjà émis. Lors du renouvellement une nouvelle “lignée” de certificats sera créée ne se trouvant pas dans le dossier de destination attendu par les services.
Ceci est du au bug https://github.com/certbot/certbot/issues/2071
Il est cependant possible d'ajouter des SAN sans problème.
Pour retirer un sous domaine, contactez Zertrin auparavant pour coordonner l'opération tant que le bug 2071 n'est pas résolu.
Quand vous ajoutez des sous-domaines dans le certificat, pensez bien à mettre à jour le script de monitoring des certificats SSL : cf ssl-cert-check
Installation
Tout se fait (pour le moment) en root
sur le serveur.
Installation du paquet certbot
apt-get install -t jessie-backports certbot
On désactive le cron bi-quotidien livré avec le paquet certbot avec dpkg-divert
car nous utilisons notre propre script de renouvellement :
sudo dpkg-divert --add --rename --divert /etc/cron.d/certbot.disabled /etc/cron.d/certbot
Création du fichier de config
Créer le dossier de config :
mkdir /etc/letsencrypt
Créer le fichier /etc/letsencrypt/cli.ini
avec le contenu suivant :
- /etc/letsencrypt/cli.ini
# Use a 4096 bit RSA key instead of 2048 rsa-key-size = 4096 # Uncomment and update to register with the specified e-mail address email = admin@federez.net # Accept the Terms of Service agree-tos = True # Uncomment to use a text interface instead of ncurses text = True authenticator = webroot webroot-path = /var/www/letsencrypt # If the requested cert matches an existing cert, always # keep the existing one until it is due for renewal keep-until-expiring = True # If an existing cert covers some subset of the requested names, # always expand and replace it with the additional names expand = True
Configuration et vérification que les conf apaches sont bien compatibles avec l'auth webroot
La première partie de la configuration ci-dessous est en cours de déploiement sur hexagon. Les autres serveurs ne sont pas configurés ainsi (pour le moment).
Pour éviter de définir pour chaque site un bloc de configuration pour HTTP afin de rediriger les navigateurs vers la version HTTPS de chaque site, on peut créer un fichier '/etc/apache2/site-available/000-no-tls.conf
' avec :
- /etc/apache2/site-available/000-no-tls.conf
<VirtualHost *:80> ServerAdmin webmaster@federez.net ServerName hexagon.federez.net RewriteEngine On RewriteCond %{HTTPS} !=on # Pas de redirection pour les requêtes de Let's Encrypt RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/.*$ # Redirection vers un domaine de federez.net RewriteCond %{HTTP_HOST} ^([^.]+\.)?federez\.(fr|eu|org|net) RewriteRule ^.*$ https://%1federez.net%{REQUEST_URI} [R,L,R=permanent] <IfModule mod_proxy.c> ProxyPass /.well-known/acme-challenge ! </IfModule> <IfModule mod_alias.c> Alias /.well-known/acme-challenge /var/www/letsencrypt/.well-known/acme-challenge </IfModule> <Directory "/var/www/letsencrypt/.well-known/acme-challenge"> AllowOverride None Require all granted </Directory> ErrorLog /var/log/apache2/no-tls.error.log CustomLog /var/log/apache2/no-tls.access.log combined LogLevel Warn </VirtualHost>
On s'assurera que le module 'mod_rewrite
' est bien chargé :
a2enmod rewrite
Ensuite, il faut l'activer avec :
a2ensite 000-no-tls
puis s'assurer qu'aucun fichier de configuration d'apache ne contient de configuration pour HTTP, et recharger la configuration d'apache :
service apache
Avec le plugin d'auth webroot, lors de l'obtention du certif un fichier au nom aléatoire créé par le client dans /var/www/letsencrypt/.well-known/acme-challenge/
va etre accédé par le backend de Let's Encrypt à l'adresse http://sous-domaine.example.net/.well-known/acme-challenge/nom-de-fichier-aleatoire
Premièrement on crée /var/www/letsencrypt/.well-known/acme-challenge
mkdir -p /var/www/letsencrypt/.well-known/acme-challenge
Pour que tous les sous-domaines servis par apache soient en mesure de servir les fichiers dans ce dossier on crée une configuration globale pour apache avec un Alias qui se charge de servir le bon dossier :
- /etc/apache2/conf-available/letsencrypt.conf
<IfModule mod_proxy.c> ProxyPass /.well-known/acme-challenge ! </IfModule> <IfModule mod_alias.c> Alias /.well-known/acme-challenge /var/www/letsencrypt/.well-known/acme-challenge </IfModule> <Directory "/var/www/letsencrypt/.well-known/acme-challenge"> Options FollowSymLinks AllowOverride None Require all granted AddDefaultCharset off </Directory>
On active la conf via a2enconf letsencrypt
.
Enfin, il faut s'assurer que les fichiers de conf ne contiennent pas de Redirect permanent /
inconditionnels de HTTP à HTTPS car la vérification n'est effectuée que sur le port 80 !
Solution : remplacer Redirect permanent /
par RedirectMatch permanent ^/(?!.well-known/)(.+)$
Méthode bourrin (mais fonctionnelle) : dans sites-available un bon coup de sed fait passer la pilule
sed -i 's#Redirect permanent /#RedirectMatch permanent ^/(?!.well-known/)(.+)$#g' *.conf
Astuce pour vérifier que tout est OK avant de tester avec Letsencrypt :
- Créer un fichier de test :
echo 'This is a test' > /var/www/letsencrypt/.well-known/acme-challenge/test
- Depuis une autre machine, utiliser le oneliner suivant pour tester l'accès à ce fichier de test (remplacer
quigon ldap-ro wiki-backup git
par les sous-domaines à tester) :
for sub in quigon ldap-ro wiki-backup git; do echo $sub; curl http://$sub.federez.net/.well-known/acme-challenge/test ; sleep 1; echo "-------------------"; done
Création du script de renouvellement automatique
Le script de renouvellement automatique se trouve dans /root/scripts/renew_letsencrypt_certificates.sh
Attention, le contenu de ce script est à adapter en fonction du serveur:
- il faut uniquement lister les domaines qui pointent réellement sur ce serveur dans la config DNS
- il faut penser à recharger/redémarrer les services adéquat sur le serveur
- /root/scripts/renew_letsencrypt_certificates.sh
#!/usr/bin/env bash # ---------------------------------- # EXAMPLE POUR QUIGON.FEDEREZ.NET # À ADAPTER EN FONCTION DU SERVEUR # ---------------------------------- #set -e #set -o pipefail PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin FULLCHAINPATH="/etc/letsencrypt/live/EXAMPLE.federez.net/fullchain.pem" if [[ -e "$FULLCHAINPATH" ]] then OLDHASH_CERT=$(sha1sum $FULLCHAINPATH | cut -d" " -f 1) else OLDHASH_CERT="nope" fi echo "Renewing federez.net with letsencrypt-auto..." # Pour le moment, il faut absolument éviter de retirer un sous-domaine de la liste des domaines # après que le certificat ait été déjà émis. Lors du renouvellement une nouvelle “lignée” de # certificats sera créée ne se trouvant pas dans le dossier de destination attendu par les services. # # Ceci est du au bug https://github.com/letsencrypt/letsencrypt/issues/2071 # # Il est cependant possible d'ajouter des SAN sans problème. /usr/bin/letsencrypt certonly --config /etc/letsencrypt/cli.ini --non-interactive \ -d quigon.federez.net \ -d ldap-ro.federez.net \ -d wiki-backup.federez.net \ -d git.federez.net \ -t NEWHASH_CERT=$(sha1sum $FULLCHAINPATH | cut -d" " -f 1) if [[ "$OLDHASH_CERT" != "$NEWHASH_CERT" ]] then SHOULD_RESTART_SERVICES=1 echo "Renewals done!" else SHOULD_RESTART_SERVICES=0 echo "INFO: No certificate renewed, will not restart services." fi # --------------------------------------------------------------------- # Ci-dessous à adapter en fonction des services présents sur le serveur # --------------------------------------------------------------------- # # exemple for pure-ftpd that needs a very specific certificate file # echo "Generating pure-ftpd's certificate..." # cat /etc/letsencrypt/live/EXAMPLE.federez.net/privkey.pem /etc/letsencrypt/live/EXAMPLE.federez.net/fullchain.pem > /etc/ssl/private/pure-ftpd.pem # restart the services only if needed if [[ "$SHOULD_RESTART_SERVICES" -eq 1 ]] then echo "Restarting services ..." /bin/systemctl reload apache2.service /bin/systemctl reload postfix.service # /bin/systemctl reload proftpd.service # /bin/systemctl restart dovecot.service # /bin/systemctl restart slapd.service fi
Tester la génération du certificat
chmod u+x /root/scripts/renew_letsencrypt_certificates.sh /root/scripts/renew_letsencrypt_certificates.sh
Mise en place dans le crontab
Créer le fichier /etc/cron.d/renew_letsencrypt_certificates_federez
:
- /etc/cron.d/renew_letsencrypt_certificates_federez
14 9 * * * root /root/scripts/renew_letsencrypt_certificates.sh 1>/dev/null
Configuration des services pour faire usage des certificats letsencrypt
Comme certains services n'ont pas les privilèges root à leur démarrage (au moins OpenLDAP), l'accès aux certificats leur a été donné par les commandes suivantes :
chown :ssl-cert /etc/letsencrypt/{archive,live} chmod g+rx /etc/letsencrypt/{archive,live}
Apache
Dans chaque VirtualHost HTTPS :
SSLEngine on SSLCertificateFile /etc/letsencrypt/live/EXAMPLE.federez.net/fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/live/EXAMPLE.federez.net/privkey.pem
Dovecot
Dans /etc/dovecot/conf.d/10-ssl.conf
:
ssl = yes ssl_cert = </etc/letsencrypt/live/EXAMPLE.federez.net/fullchain.pem ssl_key = </etc/letsencrypt/live/EXAMPLE.federez.net/privkey.pem
Freeradius
Pas nécessaire car ce sont les certificats des assos qui sont utilisés. Le Freeradius à Federez ne fonctionne qu'en tant que proxy.
OpenLDAP
Exécuter la commande suivante en root avec le fichier ci-dessous :
ldapmodify -H ldapi:/// -Y EXTERNAL -f letsencrypt.ldif
- letsencrypt.ldif
dn: cn=config changetype: modify replace: olcTLSCACertificateFile olcTLSCACertificateFile: /etc/letsencrypt/live/EXAMPLE/chain.pem - replace: olcTLSCertificateFile olcTLSCertificateFile: /etc/letsencrypt/live/EXAMPLE/cert.pem - replace: olcTLSCertificateKeyFile olcTLSCertificateKeyFile: /etc/letsencrypt/live/EXAMPLE/privkey.pem -
Si slapd n'a pas accès en lecture aux fichiers, la commande échoue :
ldap_modify: Other (e.g., implementation specific) error (80)
Postfix
Dans /etc/postfix/main.cf
:
smtpd_tls_cert_file=/etc/letsencrypt/live/EXAMPLE.federez.net/fullchain.pem smtpd_tls_key_file=/etc/letsencrypt/live/EXAMPLE.federez.net/privkey.pem smtpd_use_tls = yes
Proftpd
Dans /etc/proftpd/tls.conf
:
TLSRSACertificateFile /etc/letsencrypt/live/federez.net/fullchain.pem TLSRSACertificateKeyFile /etc/letsencrypt/live/federez.net/privkey.pem TLSProtocol TLSv1.2 TLSRequired on