On a vu précédemment comment utiliser le script “letsencrypt-auto
” pour créer des clés signés.
C'est sympa, mais je n'aime pas trop la manière dont sont organisés les fichiers dans “/etc/letsencrypt/
” : c'est confus pour moi.
Il existe une option pour signer ses propres clés.
Elle est assez simple et laisse a chacun le choix sur la manière d'organiser ses fichiers…
~~READMORE~~
Je pars de mon installation de “Let's Encrypt
” que j'ai décrit dans un article précédent.
“letsencrypt-auto
” est installé et ma petite infra nginx
est prête a recevoir les requêtes d'authentification en mode “webroot
” …
C'est grâce à une commande de la forme “letsencrypt-auto certonly --csr <FICHIER_CSR> ...
” qu'on va signer ses propres clés.
Le fichier “CSR
” est une requête de signature.
Dans l'aide, voici comment l'option --csr
est présenté:
certonly: Options for modifying how a cert is obtained --csr CSR Path to a Certificate Signing Request (CSR) in DER format; note that the .csr file *must* contain a Subject Alternative Name field for each domain you want certified. Currently --csr only works with the 'certonly' subcommand' (default: None)
Je vais expliquer toutes les étapes pour arriver a faire signer ses clés par “letsencrypt-auto
”, puis on verra le renouvellement des clés.
On va mettre en place une minuscule arborescence de fichiers |
Créer une base commune a toutes les configurations: elle sera dans “/root
”, dans sous-répertoire “le_certs
” :
# mkdir /root/le_certs
Ensuite, chaque ensemble de domaines sera dans un sous-répertoires dédiés.
On va créer un ensemble de domaines pour l'exemple, soit: “domain1
”.
# cd /root/le_certs # mkdir domain1 # cd domain1
Poursuivons dans ce sous-répertoire…
Faire un choix de taille de la clé: 2048 , 3072 ou 4096 bits ?
Certains experts vous diront que le minimum est maintenant 3072 bits. Qu'il en soit ainsi !
Création de la clé privée:
# openssl genrsa -out privkey.key 3072
On obtient un fichier “privkey.key
”.
Pour faire l'expert, on va rendre cette clé accessible uniquement par “root
” :
# chmod 0600 privkey.key
“Let's Encrypt
” exige qu'on génère une demande de signature de type “SAN”, c'est à dire, contenant 1 ou plusieurs domaines, mais dans un champ nommé “Subject Alternative Names
” …
C'est pas compliqué, il suffit de partir du modèle d'exemple de configuration suivant et de remplacer les “domainX
” par vos noms de domaines.
Donc, on va créer un fichier nommé “openssl-req.cnf
” contenant (exemple):
[req] default_md = sha256 distinguished_name = req_distinguished_name req_extensions = v3_req prompt = no [ v3_req ] subjectAltName = @alt_names [ req_distinguished_name ] CN = domain1 [alt_names] DNS.1 = ${req_distinguished_name::CN} # --- other alternative names ---------- DNS.2 = domain2 DNS.3 = domain3 # ... etc... jusqu'a DNS.100 si vous voulez.
“domain1
” est, en quelque sorte, le domaine principal: il apparaitra dans le “Subject
” du certificat final, mais sinon, il n'est ni plus ni moins important qu'un autre.
Par ailleurs, vous noterez que le “CN” (“Common Name”) doit aussi (et surtout) être déclaré dans la section “[alt_names]
” .
UPDATE : J'ai ajouté à la fin, une autre méthode pour générer une requête “SAN” en 1 ligne de commande… Je ne le conseille pas , mais c'est intéressant. |
# openssl req -new -key privkey.key -batch -config openssl-req.cnf -out request.csr
Voila:
Le fichier “request.csr
” est la demande de signature.
On peut vérifier que son contenu est correct comme ceci :
# openssl req -in request.csr -noout -text Certificate Request: Data: Version: 0 (0x0) Subject: CN=domain1 Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (3072 bit) ... Attributes: Requested Extensions: X509v3 Subject Alternative Name: DNS:domain1, DNS:domain2, DNS:domain3 Signature Algorithm: sha256WithRSAEncryption ...
Et c'est fini.
A moins qu'on change la clé privée ou la liste des domaines, on n'a plus à y toucher.
Reste plus qu'a faire signer… ou presque
Avant de signer, on va créer un fichier de configuration contenant certaines instructions indispensables, et notamment, l'endroit où seront stockés les clés signés.
On suppose que nous voulons les clés dans un sous répertoire “tmp_new ” (vous comprendrez bientôt pourquoi je fais ainsi). |
Donc, on créé un sous-dossier “tmp_new
” :
# mkdir tmp_new
On nomme le fichier de configuration “config.ini
” , et voici son contenu (exemple a adapter):
# --------------------------------- csr = /root/le_certs/domain1/request.csr # --------------------------------- cert-path = /root/le_certs/domain1/tmp_new/cert.pem fullchain-path = /root/le_certs/domain1/tmp_new/fullchain.pem chain-path = /root/le_certs/domain1/tmp_new/chain.pem # --------------------------------- email = noreply@eez.fr authenticator = webroot webroot-path = /var/www/letsencrypt-challenge text = true non-interactive = true agree-tos = true no-self-upgrade = true # ------------ #staging = true #quiet = true
Comme déjà vu: Décommentez la ligne “staging = true
” afin de générer des clés de tests .
Vous noterez qu'on demande expressément que les clés soient stockés dans “tmp_new
” …
Tout est prêt ? GO !
# letsencrypt-auto certonly --config config.ini Checking for new version... Requesting root privileges to run letsencrypt... /root/.local/share/letsencrypt/bin/letsencrypt certonly --config config.ini No handlers could be found for logger "letsencrypt.crypto_util" IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at /root/le_certs/domain1/tmp_new/0000_fullchain.pem. Your cert will expire on 2016-03-13. To obtain a new version of the certificate in the future, simply run Let's Encrypt again.
Et que voit-on dans le sous-répertoire “tmp_new
” ?
# ls -1 tmp_new/ 0000_cert.pem 0000_chain.pem 0000_fullchain.pem
Les noms sont précédés d'un numéro…
UPDATE: Ce n'est plus vrai depuis la version 0.7.0 de “letsencrypt-auto ”.Les fichiers créés n'ont plus de prefixe avec un numéro. |
Si on relance la même commande: de nouveaux certificats sont créé
Et dans le répertoire ?
# ls -1 tmp_new/ 0000_cert.pem 0000_chain.pem 0000_fullchain.pem 0001_cert.pem 0001_chain.pem 0001_fullchain.pem
Aaaah, ok.
Donc, quelques remarques:
UPDATE: Ce n'est plus vrai depuis la version 0.7.0 de “letsencrypt-auto ”.Mais la suite reste valable. |
En conséquence, il manque une petite surcouche logiciel pour être en mesure d'automatiser les traitements.
En passant, on peut toujours vérifier que les certificats sont corrects en tapant:
# openssl x509 -in tmp_new/0001_fullchain.pem -noout -text Certificate: Data: Version: 3 (0x2) Serial Number: ...
Sauf erreur, je ne crois que “letsencrypt-auto
” pourrait nous aider.
Donc, j'ai pondu un petit script bash qui va:
cur
” (pour “current
”)Nom | le_certs.sh |
---|---|
Version | 1.2 |
Date | 31/05/2017 |
md5 | 6748832ddfb37a530813adc0088c0b8a |
le_certs.sh | |
le_certs.sh.zip |
Une fois téléchargé (et éventuellement de-zippé et renommé), placer le dans le répertoire:
/usr/local/bin
# le_certs.sh <ACTION> <REPERTOIRE>
<REPERTOIRE>
est le repertoire dédié au domaine et contenant la configuration “config.ini”.
Il y a 2 actions possible:
check | Fait tout le travail pour avoir des clés |
---|---|
renew | Force un renouvèlement immédiat des clés (ne pas faire, c'est automatique avec check ) |
A SAVOIR: lorsque des nouvelles clés sont créés, un fichier nommé “/var/run/~newcerts ” est “touché” (avec la commande “touch”) |
Le script “le_certs.sh
” mettra les dernières clés dans le sous-répertoire “cur
” .
Toujours en utilisant notre exemple, la première fois on fait simplement:
# le_certs.sh check /root/le_certs/domain1
Sauf erreur, sauf panne des serveurs “Let's Encrypt
” (car ça arrive!!!), les clés sont dans “cur
”.
Pour renouveler régulièrement les clés, on fera encore:
# le_certs.sh check /root/le_certs/domain1
Mais vous noterez que rien ne se passe cette fois:
En fait, le script voit que les clés existent et sont encore valides.
Pour tester, vous pouvez forcer le renouvèlement des clés ainsi:
# le_certs.sh renew /root/le_certs/domain1
Lorsque de nouvelles clés sont misent en place, les anciennes sont déplacés dans le sous-répertoire “trash
”.
Pour automatiser le renouvèlement, on peut ajouter dans le CRON:
@daily [ -x /usr/local/bin/le_check_all.sh ] && /usr/local/bin/le_check_all.sh
Et dans ce (nouveau) script “le_check_all.sh
” , voici ce qu'on peut faire:
#!/bin/bash LE_CERTS=/usr/local/bin/le_certs.sh LE_FLAG=/var/run/~newcerts PATH=$PATH:/usr/sbin:/usr/local/bin ; # 2016/07/01 : correctif [ -x "$LE_CERTS" ] || exit 0 # ------------------------------- # Les certificats a tester... # ------------------------------- ${LE_CERTS} check /root/le_certs/domain1 # Ajouter ici d'autres domaines a tester # ------------------------------- # Et a la fin # ------------------------------- if rm "${LE_FLAG}" >/dev/null 2>&1 ; then service nginx configtest && service nginx reload fi # --------------------- # EOF
Sans oublier:
# chmod a+x le_check_all.sh
Ainsi, “nginx
” est automatiquement redémarré si de nouvelles clés apparaissent.
Bien sur, si vous utilisez cette méthode, il faut que la configuration de “nginx
” recherche les certificats dans le sous répertoire “cur
” …
Exemple:
... ssl_trusted_certificate /root/le_certs/domain1/cur/chain.pem; ssl_certificate /root/le_certs/domain1/cur/fullchain.pem; # la clé privé n'est pas dans "cur" :-) ssl_certificate_key /root/le_certs/domain1/privkey.pem; ...
Voila. C'est fini pour cette fois.
Pour mémoire…
Une autre méthode pour générer une requête de signature “SAN”: https://www.noobunbox.net/serveur/auto-hebergement/renouveler-automatiquement-certificat-ecdsa-lets-encrypt
A partir de la ligne de commande, en repartant de mon exemple, on peut faire :
# openssl req -new -sha256 -key privkey.key -subj "/CN=domain1" -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf "[SAN]\nsubjectAltName=DNS:domain1,DNS:domain2,DNS:domain3")) -out request.csr
On ne le voit pas bien, mais ça reprend la configuration par defaut (“/etc/ssl/openssl.cnf
”) en y ajoutant à la fin la section suivante:
[SAN] subjectAltName=DNS:domain1,DNS:domain2,DNS:domain3
J'admire la performance, mais comme je trouve cela un peu brouillon, je ne conseille pas son utilisation.