Outils pour utilisateurs

Outils du site


admin:services:letsencrypt

< 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.

Quand vous créez un nouveau certificat ou si vous ajoutez des sous-domaines dans un certificat existant, pensez bien à mettre à jour le script de monitoring des certificats SSL : cf ssl-cert-check

Pour les tests il faut apposer temporairement --dry-run à la commande certbot. Il est obligatoire de faire des tests jusqu'à ce que ça marche, il y a toujours des oublis ou des problèmes imprévus, et trop d'erreurs sans dry run va conduire à un blocage temporaire du coté de Let's Encrypt.

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.

Procédure d'install plus simple

Le certbot a évolué depuis le début et il n'est plus nécessaire d'effectuer des hacks aussi gros pour le faire marcher. Les plugins automatiques type apache et nginx peuvent avoir des comportements non désirés dans des configurations non usuelles, il est déconseillé de les utiliser.

On installera le certbot depuis les backports jessie ou les dépots stretch.

Il existe deux méthodes pour réaliser le challenge en HTTP :
* le serveur en standalone (qui n'est viable UNIQUEMENT si AUCUN SERVEUR WEB NE TOURNE SUR LE PORT 80)
* le webroot qui consiste à rediriger les requêtes des serveurs LE dans un dossier différent de celui de l'application web usuelle.

Nous choisirons ici la deuxième méthode.

Pour un nginx la configuration à placer dans le vhost est la suivante :

location ^~ /.well-known { root /var/www/letsencrypt; }

Il faut que le dossier existe (un coup de mkdir devrait suffire). Il doit appartenir à l'utilisateur du certbot (root par défaut) et être disponible en lecture pour www-data.

Enfin, il faut mettre en place le cron de renouvellement des certificats s'il n'a pas été ajouté lors de l'installation du certbot (dans /etc/cron.d/certbot mode 0644)

0 */12 * * * root test -x /usr/bin/certbot && perl -e 'sleep int(rand(3600))' && certbot -q renew --renew-hook "/bin/systemctl reload nginx"

On notera le renew hook qui permet de relancer les services si un nouveau certificat doit être pris en compte. On pourra faire un script pour le hook s'il n'est pas une commande courte et simple.

Tout est prêt pour générer le certificat :)

Il suffit de placer une commande du type :

certbot certonly --cert-name mon.certificat.tld --rsa-key-size 4096 \
--email admin@federez.net --webroot -w /var/www/letsencrypt -d domain1.tld -d domain2.tld

La première fois on vous demandera de dire oui aux TOSS.

Rappel: Pour les tests il faut apposer temporairement --dry-run à la commande certbot. Il est obligatoire de faire des tests jusqu'à ce que ça marche, il y a toujours des oublis ou des problèmes imprévus, et trop d'erreurs sans dry run va conduire à un blocage temporaire du coté de Let's Encrypt.

Si on veut étendre un certificat existant on peut placer un --extend et il faut mettre le même nom.

Pour avoir une idée de quels certificats sont existants un certbot certificates marche très bien.

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.

Précédemment, il fallait 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 était créée ne se trouvant pas dans le dossier de destination attendu par les services.

Ceci était du au bug https://github.com/certbot/certbot/issues/2071

Il était cependant possible d'ajouter des SAN sans problème.

Désormais, il suffit que l'option --cert-name soit donnée quand on appelle certbot. Cela définit la “lignée” de certificats et donc, si on retire un sous domaine de la liste, il comprendra que c'est bien ce qu'on veut faire.

Installation

Tout se fait (pour le moment) en root sur le serveur.

Installation du paquet certbot

apt-get install 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

On désactive aussi le service et le timer systemd qui viennent en doublon du fichier de cron :

systemctl stop certbot.service certbot.timer
systemctl disable certbot.service certbot.timer
systemctl mask certbot.service certbot.timer

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

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 é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/sites-available/000-no-tls.conf' avec :

/etc/apache2/sites-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
                # Utilité à confirmer :
                # Options FollowSymLinks
                # AddDefaultCharset off
        </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 activer la configuration du site qui gère HTTP avec :

a2ensite 000-no-tls

Enfin, on peut supprimer tous les VHOST HTTP pour ne laisser que les blocs qui concernent HTTPS dans les fichiers de configuration d'Apache.

Notamment, s'il n'est pas utilisé pour autre chose, il faut désactiver la config 000-default.conf avec a2dissite 000-default.conf. Sinon il prend précédence sur le 000-no-tls.conf qu'on vient de définir.

Puis on recharge la configuration d'apache :

service apache2 reload

Astuce pour vérifier que tout est OK avant de tester avec Letsencrypt :

  1. Créer un fichier de test : echo 'This is a test' > /var/www/letsencrypt/.well-known/acme-challenge/test
  2. 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) :
  3. s'assurer de voir This is a test retourné pour chaque sous domaine (et donc pas une erreur 404).
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 EXMAPLE.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
 
# remplacer avec le bon chemin, cf le --cert-name ci-dessous
FULLCHAINPATH="/etc/letsencrypt/live/EXMAPLE.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..."
 
# Bien s'assurer que le --cert-name est défini, sinon il y aura des problèmes si on veut retirer des domaines.
# De préférence mettre le meme nom que le premier domaine demandé, qui est de préférence le FQDN du serveur.
 
/usr/bin/letsencrypt certonly --config /etc/letsencrypt/cli.ini --non-interactive --quiet \
  --cert-name EXMAPLE.federez.net \
  -d EXMAPLE.federez.net \
  -d ldap-ro.federez.net \
  -d wiki-backup.federez.net \
  -d git.federez.net \
  --text
 
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

Rappel: Pour les tests penser à apposer temporairement --dry-run à la commande certbot dans le script. Il est obligatoire de faire des tests jusqu'à ce que ça marche, il y a toujours des oublis ou des problèmes imprévus, et trop d'erreurs sans dry run va conduire à un blocage temporaire du coté de Let's Encrypt.

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

Prosody

Dans /etc/prosody/prosody.cfg.lua :

ssl = {
        key = "/etc/letsencrypt/live/EXAMPLE.federez.net/privkey.pem";
        certificate = "/etc/letsencrypt/live/EXAMPLE.federez.net/fullchain.pem";
}
1)
le protocole pour obtenir un certificat automatiquement
admin/services/letsencrypt.txt · Dernière modification: 2020/06/17 18:23 de zertrin