ReLoad

Thierry Jaouen ~ WikiBlog
"Rien à foutre d'être lu, tant que je peux me relire."

Outils pour utilisateurs

Outils du site


blog:2016:04:15:let_s_encrypt_faire_signer_ses_propres_cles

Let's Encrypt: Faire signer ses propres clés

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…

Pré-requis

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” …

Option --csr

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.

Organisation des domaines

:!: 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…

Création de la clé privée

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

Requête multi-domaine

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.

Générer la demande de signature

# 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 :-)

Faire signer un CSR

Un fichier de configuration

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” …

Premier test

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:

  1. Les clés sont recréés sans tester leurs dates de péremptions.
  2. Les noms changent a chaque fois, sans écraser les fichiers précédents.
:!: 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:
...

Un script a la rescousse

Sauf erreur, je ne crois que “letsencrypt-auto” pourrait nous aider.

Donc, j'ai pondu un petit script bash qui va:

  1. Si besoin: créer de nouvelles clés.
  2. Récupérer les dernières clés en faisant fi du nom.
  3. Vérifier qu'elles sont fonctionnelles.
  4. Faire un backup des clés actuellement en usage.
  5. Installer ces clés dans le sous répertoire “cur” (pour “current”)
  6. Informer l'environnement que de nouvelles clés sont arrivés
  7. Faire le ménage dans ses backups.

Le script

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

Usages

# 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”)
Où sont les clés ?

Le script “le_certs.sh” mettra les dernières clés dans le sous-répertoire “cur” .

Exemples

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

renew All

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

Tips

Pour mémoire…

Générer un certificat "SAN" en 1 ligne de commande

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

Comments

Salut Thierry

Merci pour ton aide concernant le script ca fonctionne :)

Sinon pas mal cette manière de créer un CSR, effectivement c'est beaucoup plus propre :)

1 | | 2016/04/16 14:08 | reply



Si vous ne pouvez pas lire le code, téléchargez ce fichier .wav pour l'écouter.
blog/2016/04/15/let_s_encrypt_faire_signer_ses_propres_cles.txt · Dernière modification: 2017/05/31 11:45 par thierry