Journal Reparlons de Let’s Encrypt

Posté par (page perso) . Licence CC by-sa
61
23
fév.
2016
Ce journal a été promu en dépêche : Reparlons de Let’s Encrypt.

Sommaire

Dans le dernier journal où il était question de Let’s Encrypt, des commentateurs ont demandé des retours d’expérience :

On est sur Linuxfr, moi je t'aurais surtout demandé "Comment ?". J'ai l'intention de m'y mettre aussi mais j'ai pas encore franchi le pas et j'aimerais avoir des retours d'expérience.

L’auteur du journal a répondu que Let’s Encrypt était « suffisamment simple d’utilisation pour qu’il ne soit pas nécessaire [de s’]étendre sur le sujet. »

Je disconviens respectueusement. Questions à se poser, pièges à éviter, bonnes ou mauvaises pratiques… Je pense au contraire qu’il y a largement matière à s’étendre sur l’utilisation de Let’s Encrypt.

Ce journal est donc un ensemble pas forcément cohérent de réflexions sur des points divers et variés (sans aucune prétention à l’exhaustivité), agrémentées d’un peu de « retours d’expérience » et de conseils (qui valent ce qu’ils valent).

Dans ce journal, j’essaierai de me tenir à la convention suivante : Let’s Encrypt (en deux mots) désignera l’autorité de certification délivrant des certificats par l’intermédiaire du protocole ACME (Automatic Certificate Management Environment), tandis que Letsencrypt (en un seul mot) désignera le client ACME officiel.

Principe de fonctionnement de Letsencrypt

La facilité d’utilisation promise par Let’s Encrypt repose en réalité principalement sur le client Letsencrypt et sur l’automatisation qu’il propose.

Letsencrypt s’occupe (ou peut s’occuper) de deux tâches distinctes : ① obtenir un certificat pour le(s) domaine(s) souhaité(s), et ② installer le certificat obtenu.

Pour obtenir un certificat, Letsencrypt

  • génère une paire de clefs et une demande de signature de certificat (Certificate Signing Request, CSR) ;
  • envoie la demande à un serveur ACME ;
  • répond aux défis d’authentification (challenges) posés par le serveur, permettant au demandeur de prouver qu’il contrôle le(s) domaine(s) demandé(s) ;
  • reçoit le certificat signé en retour.

Une fois le certificat obtenu, le client installe le certificat proprement dit, la clef privée correspondante, et les certificats intermédiaires là où le serveur web pourra les trouver, et configure et relance ledit serveur s’il sait le faire (si le serveur en question est Apache HTTP ou Nginx, pour l’instant).

Letsencrypt garde aussi une trace des certificats obtenus. Lancé à intervalle régulier, il répétera automatiquement la procédure s’il détecte qu’un certificat est sur le point d’expirer.

En définitive, le but est clairement que l’administrateur puisse mettre en place TLS en une seule commande, avant d’oublier jusqu’à l’existence même de Let’s Encrypt.

Le mode « staging »

Si vous voulez tester Letsencrypt, que ce soit parce que vous n’êtes pas encore sûr de vouloir l’utiliser, parce que vous voulez vérifier s’il fonctionne dans votre configuration (une très bonne idée, parce qu’une des limites de l’automatisation est qu’il suffit parfois de peu de choses pour la faire capoter), ou que vous voulez bidouiller le client, pensez à l’option --staging.

Avec cette option, le client passe par toutes les étapes mentionnées ci-dessus, mais le certificat obtenu est signé par une pseudo-CA (“happy hacker fake CA”) réservés aux tests.

Le principal intérêt est de pouvoir vous livrer à autant de tests que vous avez besoin, sans vous heurter aux limitations fixées par Let’s Encrypt (notamment, la limite de cinq certificats par semaine pour un domaine donné).

Une fois que votre décision est prise, que vous savez que le client fonctionne comme vous l’attendez, ou que vous êtes satisfait de votre bidouillage, retirez simplement l’option --staging pour demander un certificat auprès de la véritable autorité Let’s Encrypt.

L’authentification HTTP-01

Le protocole ACME propose plusieurs types de défis pour vérifier la légitimité du client sur un domaine. Le plus important pour l’instant est le défi HTTP-01.

Si Alice demande un certificat pour example.com, le défi HTTP-01 consistera pour elle à rendre accessible sur la machine example.com, par HTTP sur le port 80, un fichier .well-known/acme-challenge/token, où token est une valeur aléatoire générée pour l’occasion par le serveur ACME. Le fichier devra contenir le même token, suivi d’un condensat de la clef associée au compte ACME d’Alice.

Le client Letsencrypt se charge normalement tout seul de répondre à ce défi, soit en plaçant le fichier demandé à la racine d’un serveur web qui par ailleurs est déjà en service sur la machine, soit en se plaçant lui-même en écoute sur le port 80.

Si vous avez déjà un serveur web opérationnel, vous choisirez probablement la première méthode (la seconde vous oblige à couper temporairement le serveur pré-existant).

Dans ce cas, assurez-vous que la configuration actuelle du serveur autorise l’accès à .well-known. Plusieurs applications web viennent avec un fichier .htaccess qui par défaut restreint l’accès à ce dossier, comme par exemple Drupal (cas rapporté ici) ou Owncloud (testé par votre serviteur).

Avec Owncloud 8.x, la ligne responsable dans le .htaccess est la suivante :

  RewriteRule ^(\.|autotest|occ|issue|indie|db_|console).* [R=404,L]

qui interdit l’accès, entre autres, à tout fichier ou dossier dont le nom commence par un point. Insérez avant cette ligne une règle autorisant spécifiquement l’accès au dossier des défis ACME :

  RewriteRule ^\.well-known/acme-challenge/ - [L]

Je mentionne ce cas pour illustrer ce que j’ai appelé plus haut les limites de l’automatisation : Letsencrypt tente de tout faire tout seul, mais ses développeurs ne peuvent pas tout prévoir et il y a aura toujours des cas où l’administrateur devra aller voir lui-même ce qui se passe.

Utiliser Letsencrypt ailleurs que sur le serveur de production

Le client Letsencrypt est conçu pour être exécuté directement sur le serveur sur lequel le certificat demandé sera utilisé. Cela au nom de la facilité d’utilisation et de l’automatisation : c’est ce qui permet au client à la fois de répondre aux défis d’authentification, et de configurer le serveur pour utiliser le certificat obtenu.

Le problème que j’ai avec ça, c’est que ça implique donc de faire tourner, sur un serveur de production, un gros morceau de code qui

  • est clairement estampillé BETA SOFTWARE,
  • nécessite les privilèges du super-utilisateur,
  • manipule directement des clefs cryptographiques,
  • joue avec les paquets installés sur le système,
  • tripatouille les fichiers de configuration des logiciels serveurs.

What could possibly go wrong?

Au passage, le disclaimer sur l’état du client (“should be tested thoroughly in staging environments before use on production systems”), même s’il est de bon sens, me semble assez décalé par rapport à la cible de Let’s Encrypt. Combien d’administrateurs en herbe ont un serveur de pré-production ?

Pour ma part, il est simplement hors de question que j’utilise ce client dans ces conditions. Question de principe.

Pour les râleurs utilisateurs dans mon genre, il y a plusieurs solutions.

La première est d’utiliser un autre client que le client officiel Letsencrypt. Ce n’est pas le choix qui manque. Le nom de certains d’entre eux, ou leur façon d’insister sur leur caractère simple, minimaliste (SimpLE, ACME Tiny (~200 lines), a relatively simple bash-script, simplest shell script, a tiny script (~400 lines), lightweight manual-workflow, no magical webserver auto-configuration, etc.) ou le fait qu’ils ne requièrent pas de privilèges (No Sudo Client, obviously runs without root access), me fait dire que je ne suis pas seul à trouver le client officiel un peu bloated.

La seconde est d’utiliser quand même le client officiel (spontanément, j’ai quand même un peu plus confiance dans ce client que dans un script de 200 lignes que je soupçonne d’avoir été pondu à LA RACHE — je connais bien ce genre de scripts, pour en écrire moi-même régulièrement…), mais avec la commande certonly, qui se contente d’obtenir un certificat sans chercher à l’installer, et l’option --manual, qui laisse l’administrateur répondre aux défis d’authentification lui-même. La combinaison des deux permet d’utiliser le client sur une machine distincte du serveur où le certificat sera utilisé.

Rajoutez encore les options --config-dir, --work-dir et --logs-dir pour changer les dossiers de travail de Letsencrypt (qui par défaut veut absolument écrire dans /etc/letsencrypt, /var/lib/letsencrypt et /var/log/letsencrypt), et le client n’a plus besoin de privilèges particuliers.

Le problème évident avec cette solution, c’est son caractère manuel. « Répondre soi-même aux défis d’authentification » (c’est-à-dire, aller déposer manuellement sur le serveur le bon fichier dans .well-known/acme-challenge, avec la valeur du token affiché par le client) est fastidieux et error-prone, surtout si vous demandez un certificat pour plus de deux ou trois domaines). Et la perspective de devoir recommencer tous les trois mois est peu engageante au possible.

Reste la troisième solution, qui est celle que j’ai choisie : adapter le comportement du client officiel pour avoir les avantages de l’authentification manuelle (pas besoin de lancer le client sur le serveur) tout en permettant une certaine automatisation. Letsencrypt a le bon goût d’être modulaire (les méthodes d’authentification sont implémentées sous la forme de greffons), donc on peut faire ça « proprement » dans un greffon séparé sans aller bidouiller honteusement le code du client comme un sagouin.

J’ai donc commis (à LA RACHE, bien sûr, faut pas déconner quand même) le greffon letsencrypt-ssh, qui permet de répondre aux défis d’authentification en exécutant un script à travers une connexion SSH.

En définitive, j’invoque Letsencrypt (sur mon poste de travail, pas sur mon serveur) à peu près comme suit :

$ letsencrypt \
    --certonly \
    --config ~/.config/letsencrypt/letsencrypt.conf \
    --csr cert.csr \
    --cert-path cert.pem \
    --chain-path chain.pem \
    --fullchain-path cert+chain.pem \
    --authenticator letsencrypt-ssh:ssh \
    --letsencrypt-ssh:ssh-server root@myserver.example.com \
    --domains example.com,www.example.com,nimportequoi.example.com

avec le contenu suivant dans ~/.config/letsencrypt/letsencrypt.conf :

config-dir = /home/alice/.config/letsencrypt
work-dir = /home/alice/.local/share/letsencrypt
logs-dir = /home/alice/.local/share/letsencrypt
email = alice@example.com
non-interactive
agree-tos

cert.csr est la demande de signature de certificat (Certificate Signing Request), générée « classiquement » avec openssl req (voir plus bas pourquoi je fournis moi-même la CSR au lieu de laisser Letsencrypt la générer lui-même — en gros, c’est pour pouvoir gérer les clefs privées à ma guise).

Si la demande est accordée, le résultat est le certificat proprement dit dans 0000_cert.pem, le certificat intermédiaire dans 0000_chain.pem, et la concaténation des deux (directement utilisable avec la plupart des logiciels serveurs) dans 0000_cert+chain.pem. (Le préfixe nnnn est automatiquement ajouté par Letsencrypt ; il est incrémenté si besoin est pour éviter d’écraser un fichier pré-existant.)

Letsencrypt et l’épinglage des clefs

L’épinglage (pinning) des clefs désigne un ensemble de méthodes par lesquelles un site peut désigner à ses visiteurs les clefs publiques ou les certificats qu’il utilise.

Il y a principalement trois méthodes d’épinglage, qui diffèrent par l’endroit où l’on plante l’épingle.

  • Directement dans le code du navigateur. Cette méthode est née quand les développeurs de Chrome ont épinglé les clefs des sites de Google dans leur navigateur, puis s’est peu à peu étendue à la fois à d’autres navigateurs (Firefox à partir de la version 32) et à une poignée d’autres « sites sensibles » sélectionnés manuellement.

Je ne m’étendrai pas davantage sur cette méthode, qui par définition est du seul ressort des éditeurs de navigateurs. Si votre site est suffisamment « gros » ou « sensible » pour être éligible à ce type d’épinglage, vous n’avez pas besoin de ce journal pour savoir ce que vous avez à faire…

  • Dans les en-têtes HTTP. C’est le HTTP Public Key Pinning (HPKP), normalisé dans le RFC 7469. C’est la forme la plus répandue d’épinglage aujourd’hui, pour deux raisons : c’est la plus facile à déployer pour l’administrateur du site web et elle est pleinement prise en charge par Chrome et Firefox. Elle a pour inconvénient de ne pas pouvoir protéger l’utilisateur lors de sa première visite sur le site.

  • Dans le DNS. C’est le DNS-based Authentication of Named Entities (DANE), normalisé dans le RFC 6698. Cette méthode a le double avantage, par rapport à la précédente, de n’être pas limitée au protocole HTTP et d’être efficace dès la première connexion. Elle a le double inconvénient d’être plus délicate à déployer côté serveur — parce qu’il faut déployer DNSSEC au préalable (si DNSSEC est déjà en place, rajouter DANE par dessus est trivial) — et pas du tout prise en charge nativement côté client (en tout cas par les navigateurs, donc pour HTTP — la situation est plus engageante dans le monde du courrier électronique, avec notamment une pleine prise en charge par Postfix).

DANE permet aussi d’épingler les certificats plutôt que les clefs publiques. Je ne m’attarderai pas ici sur cette possibilité.

Quelle que soit la méthode (notez qu’elles sont combinables, vous pouvez épingler dans les en-têtes HTTP et dans le DNS), l’épinglage nécessite au préalable de réfléchir à trois questions :

  • quelle(s) clef(s) épingler ?
  • pour combien de temps ?
  • comment gère-t-on le changement de clef ?

Quelle(s) clef(s) épingler ?

Vous pouvez épingler la clef de n’importe lequel des certificats constituant votre chaîne de certification, depuis le propre certificat du serveur jusqu’au certificat racine de l’autorité de certification.

Dans le cas de Let’s Encrypt, la chaîne de certification est à trois maillons :

  • votre certificat,
  • le certificat intermédiaire Let’s Encrypt Authority X1,
  • le certificat racine DST Root CA X3.

Épingler la clef du certificat racine est à mon avis toujours une mauvaise idée (que ce soit avec Let’s Encrypt ou n’importe quelle autre autorité de certification) : d’une part vous donnez trop de pouvoir à la CA, d’autre part et surtout ce n’est pas vous qui décidez à quelle racine votre chaîne de certification va être rattachée. Par le jeu des signatures croisées entre autorités de certification, une même chaîne peut être rattachée à plusieurs racines, et c’est le navigateur qui décide seul comment reconstruire la chaîne globale.

Épingler la clef du certificat intermédiaire n’est pas une mauvaise solution, à condition d’être conscient de deux écueils. D’une part, il est toujours possible que ce certificat intermédiaire change à l’avenir, ce qui casserait votre épingle (un tel changement serait probablement annoncé à l’avance par Let’s Encrypt, mais encore faut-il se tenir au courant — et il y a aussi le risque d’un changement à l’improviste, en cas de compromission). D’autre part, cela pose un problème épineux lors du choix de la clef de secours (voir plus loin).

Reste l’épinglage de la clef de votre certificat, qui est (vous m’avez vu venir) à mon sens la meilleure solution. C’est à la fois plus sûr (vous vous protégez contre d’éventuelles malversations de toutes les CA, y compris Let’s Encrypt, alors que l’épinglage d’une clef parente vous protège « seulement » contre les CA autres que Let’s Encrypt), et ça vous donne plus de flexibilité quand il s’agit de remplacer la clef — puisque vous décidez à quel moment vous changez de clef, et donc à quel moment vous devez mettre à jour votre épingle.

Malheureusement, cette dernière solution est celle qui ne fonctionne pas out-of-the-box avec Letsencrypt. Par défaut en effet, le client génère automatiquement une nouvelle clef à chaque renouvellement du certificat, ne vous laissant pas la main-mise nécessaire à la bonne gestion des épingles.

Pas d’obstacle insurmontable, mais il faut renoncer à ce comportement par défaut et prendre en charge vous-même la gestion des clefs de vos certificats, et fournir à Letsencrypt, via l’option --csr, une CSR pré-générée par vos soins — cela désactive de fait la génération automatique d’une nouvelle clef.

La durée de l’épinglage

Le choix de la durée de l’épinglage (paramètre max-age dans un en-tête Public-Key-Pins) est dictée par deux considérations :

  • une durée trop courte risque de faire perdre le bénéfice de l’épinglage aux visiteurs occasionnels (par exemple, un épinglage de trois jours ne servirait à rien pour quelqu’un qui visite votre site en moyenne une fois par semaine) ;
  • une durée trop longue augmente la période d’indisponibilité de votre site si jamais les clefs épinglées venaient à ne plus correspondre aux clefs réellement utilisées pour quelque raison que ce soit (typiquement, une erreur de votre part…).

Le RFC 7469, annexe B suggère de commencer par une durée de l’ordre de quelques minutes à quelques heures, puis d’augmenter progressivement cette durée. En gardant à l’esprit que les navigateurs peuvent imposer une borne supérieure, laissée à leur discrétion (mais le RFC suggère environ 60 jours, §4.1).

Pour ma part, j’ai opté pour un alignement avec la durée de validité des certificats délivrés par Let’s Encrypt, soit 90 jours. Mais ce n’est aucunement nécessaire, souvenez-vous qu’on épingle ici des clefs (qui sont valables aussi longtemps que vous le décidez) et non des certificats.

Dans le cas de l’épinglage dans le DNS, il n’y a pas d’équivalent explicite au paramètre max-age, mais la période de validité de la signature de l’enregistrement TLSA en tient lieu.

Épinglage et changement de clefs

Quelle que soit la clef épinglée, anticiper son changement est crucial. Si une clef épinglée change subitement sans que l’épingle n’ait été mise à jour à l’avance, les visiteurs ne pourront plus se connecter au site tant que l’ancienne épingle n’aura pas expirée.

Comme il n’est pour autant pas possible de changer une épingle tant que la clef correspondante est toujours utilisée, la seule solution viable est d’épingler en permanence au moins deux clefs : une clef en cours d’utilisation, et la clef qui la remplacera dans le futur.

Ce double épinglage est d’ailleurs formellement obligatoire dans le cas de l’épinglage dans les en-têtes HTTP : le RFC 7469 interdit aux navigateurs de tenir compte d’un en-tête Public-Key-Pins qui ne comporterait pas (au moins) une « épingle de secours » (backup pin), c’est-à-dire l’épingle d’une clef absente de la chaîne de certification actuelle (§4.3).

Si vous avez choisi d’épingler la clef d’un certificat intermédiaire ou du certificat racine, vous devez maintenant vous demander : quelle clef de secours allez-vous épingler ? La recommandation dans ce cas de figure est d’épingler une clef équivalente d’une autre autorité de certification — l’autorité vers laquelle vous avez prévu de vous retourner en cas de problème avec Let’s Encrypt.

Si au contraire vous avez choisi d’épingler la clef de votre propre certificat, il vous suffit de générer initialement non pas une mais deux clefs : une que vous utiliserez pour générer la CSR et obtenir un certificat de Let’s Encrypt (et qui se retrouvera donc sur votre serveur), et une dont vous prendrez juste l’empreinte avant de la mettre bien à l’abri (ailleurs que sur votre serveur).

Comme déjà vu plus haut, cela implique de renoncer à la génération automatique des clefs qui est le comportement par défaut de Letsencrypt.

Lorsque vous déciderez qu’il est temps de changer de clef, il vous faudra alors :

  • générer une nouvelle CSR à partir de la clef de secours (qui devient la clef « active »),
  • renouveller le certificat en utilisant la CSR fraîchement générée,
  • générer une nouvelle clef de secours,
  • mettre à jour les épingles pour y ajouter la nouvelle clef de secours (et supprimer l’ancienne clef).

Notez que dès l’instant où vous gérez les clefs vous-mêmes au lieu de laisser Letsencrypt le faire, rien ne vous oblige à procéder à ce changement à chaque renouvellement du certificat. Vous seul décidez de la fréquence de rotation des clefs (hors le cas où une compromission de votre clef actuelle vous oblige à activer prématurément la clef de secours) : ce peut être à chaque renouvellement (donc tous les trois mois environs), mais aussi un renouvellement sur deux, un renouvellement sur cinq…

Let’s Encrypt et OCSP

Une des principales craintes de l’équipe de Let’s Encrypt sur la viabilité du projet concerne la charge des serveurs OCSP. Délivrer un certificat est un acte unique qui ne coûte pas grand’chose, mais pour chaque certificat délivré, Let’s Encrypt doit être prêt à répondre à quiconque demande si le certificat est toujours valide ou bien s’il a été révoqué, et ce pour la durée de vie du certificat.

C’est l’une des raisons derrière, à la fois, la décision de limiter la validité des certificats à 90 jours (passé ces 90 jours, un client n’a plus besoin de solliciter le serveur OCSP, la date d’expiration suffit à dire que le certificat n’est plus valable), et la décision de limiter le nombre de demandes de certifiats à 5 par domaine et par semaine.

Vous pouvez contribuer à alléger la charge pesant sur Let’s Encrypt en configurant votre serveur pour fournir lui-même les réponses OCSP à vos clients. C’est l’épinglage OCSP (OCSP stapling, RFC 6066 §8).

Le principe est que c’est votre serveur, et non vos clients, qui ira périodiquement s’enquérir auprès du serveur OCSP de Let’s Encrypt (dont l’adresse est mentionné dans le certificat) de l’état du certificat. À la connexion d’un client, si celui-ci prend en charge les épingles OCSP (c’est le cas à ma connaissance de tous les navigateurs courants), le serveur lui enverra la réponse OCSP en même temps que le certificat, dispensant ainsi le client d’aller contacter lui-même le serveur OCSP de l’autorité de certification (réduisant par là non seulement la charge dudit serveur, mais aussi une fuite d’informations sur les sites visités par le client).

À l’heure actuelle, même si vous laissez Letsencrypt configurer automatiquement votre serveur, il n’active pas l’épinglage OCSP. Vous devez donc le faire vous-même si votre serveur le prend en charge.

Avec Apache 2.4 :

SSLUseStapling on
SSLStaplingCache shmcb:/var/lib/httpd/ssl_stapling(512000)

(Reportez-vous à la documentation du module ssl pour le détail des options SSLStapling*.)

Let’s Encrypt et Certificate Transparency

Let’s Encrypt soumet automatiquement les certificats générés à plusieurs opérateurs de journaux Certificate Transparency (RFC 6962). Toutefois, les jetons CT correspondants ne sont pas inclus dans le certificat délivré, et ne sont apparemment pas inclus non plus dans les réponses OCSP.

Cela veut dire que si vous voulez fournir les jetons CT à vos visiteurs, il ne vous reste que la méthode de l’extension TLS, ce qui peut poser deux problèmes :

  • votre serveur web doit prendre en charge l’extension en question, ce qui est le cas de peu de serveurs aujourd’hui, du moins dans leurs versions stables (pour Apache HTTP, il faut la version de développement et le module ssl-ct) ;
  • il vous faut récupérer les jetons auprès des opérateurs de journaux, et il ne semble pas y avoir de moyen direct de faire ça — le plus simple est a priori de carrément re-soumettre vous-même le certificat (avec ct-submit par exemple), en espérant que l’opérateur du journal accepte de vous redonner le jeton correspondant (le RFC 6962 autorise ce comportement mais ne l’impose pas, l’opérateur pourrait simplement rejeter votre soumission au motif que le certificat a déjà été ajouté au journal).

Gardez toutefois à l’esprit qu’aucun navigateur n’exige de jetons CT pour valider un certificat. Seul Chrome exige de tels jetons, seulement pour les certificats « à validation étendue » (Extended Validation, EV), et seulement pour afficher la « barre verte » associée à ce type de certificats (sans jetons CT, le certificat est toujours accepté, mais pas comme un certificat EV). Les certificats délivrés par Let’s Encrypt étant Domain-Validated, les jetons CT n’apportent rien de plus.

Au passage, je ne suis pas sûr que les opérateurs de journaux CT voient d’un très bon œil le fait que Let’s Encrypt leur soumettent ses certificats. Les serveurs de journaux ont été dimensionnés pour enregistrer des certificats EV dont le nombre est relativement faible (moins de 5% de tous les certificats), pas des certificats DV générés par millions et qui plus est renouvelés tous les trois mois…


Trouver quelques mots de conclusion à mettre ici. Inviter les trolls lecteurs à discuter davantage dans les commentaires. Et surtout, penser à enlever cette ligne avant de publier.

  • # Client officiel sans root

    Posté par (page perso) . Évalué à 3. Dernière modification le 23/02/16 à 12:49.

    OK alors j'avoue que je n'ai pas tout lu, mais je voudrais quand même mentionner que pour ma part, j'utilise le client officiel sur mon serveur de prod, pas en root, en certonly et il juste marche. J'ai un petit script simple pour automatiser un peu l'appel :

    DOMAINS="example.com www.example.com"
    EMAIL="moi@example.com"
    
    SCRIPT=$(realpath "$0")
    DIR=$(dirname "$SCRIPT")
    
    CERTS="$DIR/cert"
    WWW="$DIR/www"
    
    LE_CERTS="$CERTS/letsencrypt"
    
    mkdir -p "$LE_CERTS"
    
    DOMAINS_ARG=""
    for DOMAIN in $DOMAINS; do
        DOMAINS_ARG="${DOMAINS_ARG} -d ${DOMAIN}"
    done
    
    letsencrypt certonly -t --agree-tos --renew-by-default --email "$EMAIL" --webroot -w "$WWW" $DOMAINS_ARG --logs-dir "$LE_CERTS" --work-dir "$LE_CERTS" --config-dir "$LE_CERTS"

    Le script met les certificats dans le dossier cert/letsencrypt (relatif au script qui est à la racine de mon domaine – pas le document root bien sûr, mais le dossier dans lequel se trouvent le document root, les logs, certificats, etc). Mon serveur web est configuré pour utiliser comme certificats ceux se trouvant dans cert/letsencrypt/live/example.com/*.pem.

    Le client indique que n'étant pas lancé en root, il se peut que des trucs ne marchent pas, mais en réalité sa marchent très bien tout seul. Il ne cherche pas à toucher à ma configuration (il n'en aurait pas les droits de toute façon) ni à installer des paquets (je doute qu'il sache utiliser mon package manager) ni quoi que ce soit. Ça fait quelques mois maintenant, et je renouvelle les certificats tous les mois.

    • [^] # Re: Client officiel sans root

      Posté par . Évalué à 7.

      Si tu avais tout lu, c'est ce qui est dit dans le post…

      Rajoutez encore les options --config-dir, --work-dir et --logs-dir pour changer les dossiers de travail de Letsencrypt (qui par défaut veut absolument écrire dans /etc/letsencrypt, /var/lib/letsencrypt et /var/log/letsencrypt), et le client n’a plus besoin de privilèges particuliers.

      • [^] # Re: Client officiel sans root

        Posté par (page perso) . Évalué à 1.

        Ah pourtant j'ai dû survoler ça, mais ce paragraphe est suivi de :

        Le problème évident avec cette solution, c’est son caractère manuel

        Alors que ça n'a rien à voir avec la validation manuelle. Du coup j'ai l'impression que tout le journal n'est dû qu'à une incompréhension du fonctionnement de l'outil.

        • [^] # Re: Client officiel sans root

          Posté par (page perso) . Évalué à 4.

          Le problème évident avec cette solution, c’est son caractère manuel

          Alors que ça n'a rien à voir avec la validation manuelle.

          La solution à laquelle je fais référence dans cette phrase est celle qui consiste à utiliser à la fois la commande certonly et l’option --manual.

          Je rappelle que le premier but recherché, dans cette section, était non pas tant d’éviter de lancer le client avec les privilèges du super-utilisateur (pour ça, --manual n’est en effet pas forcément nécessaire), mais surtout d’éviter de lancer le client sur le serveur (peu importe ses privilèges).

          Et pour ça, avec le client officiel l’option --manual est indispensable, toutes les autres méthodes d’authentification (standalone ou webroot) supposent que le client est sur le serveur — sauf à utiliser la méthode sshfs proposée par ɹǝıʌıʃO (méthode très élégante d’ailleurs, je m’en veux de ne pas y avoir pensé).

    • [^] # Re: Client officiel sans root

      Posté par . Évalué à 4.

      Juste parce que j'ai la tête dans du shell en ce moment, si tu utilise bash :

      DOMAINS=("example.com" "www.example.com")
      EMAIL="moi@example.com"
      
      SCRIPT=$(realpath "$0")
      DIR=$(dirname "$SCRIPT")
      
      CERTS="$DIR/cert"
      WWW="$DIR/www"
      
      LE_CERTS="$CERTS/letsencrypt"
      
      mkdir -p "$LE_CERTS"
      
      DOMAINS_ARG=$(printf -- " -d %s" "${DOMAINS[@]}")
      
      letsencrypt certonly -t --agree-tos --renew-by-default --email "$EMAIL" --webroot -w "$WWW" $DOMAINS_ARG --logs-dir "$LE_CERTS" --work-dir "$LE_CERTS" --config-dir "$LE_CERTS"

      Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

  • # Utiliser le client officiel letsencrypt sur un autre serveur en mode automatique

    Posté par . Évalué à 6.

    Le client officiel letsencrypt fonctionne très bien sur un autre serveur que celui de production, avec --certonly mais sans --manual, en montant le webroot du serveur web sur le serveur qui exécute letsencrypt par sshfs. Il ne reste plus qu'à copier le certificat sur le serveur web par scp, et le tour est joué.

  • # Gros script qui fait trop de chose

    Posté par (page perso) . Évalué à 7.

    J'ai testé Let's Encrypt la semaine dernière.

    Alors pour commencer c'est un vrai bonheur d'avoir des certificats qui fonctionnent, rapidement, gratuitement et sans se prendre la tête. En gros, plus besoin de se cogner le site de startssl.

    Ils insistent à fond sur l'extrême simplicité pour tout mettre en place avec 3 lignes de codes… Mais comme l'auteur du journal, perso je ne veux pas sur mon serveur utiliser git pour récupérer un script qui va faire autant de chose sans me demander mon avis. Par exemple au premier lancement leur script auto télécharge et installe 40 paquets de dépendances sans même demander une confirmation. Je trouve également gênant que la commande par défaut mise en avant sur le site se permette d'aller trifouiller les fichiers de configuration d'Apache.

    Pour moi, Let's Encrypt sera vraiment simple quand il y aura un client bien fait inclus dans ma distribution (ils annoncent que des paquets pour Debian 8 seront disponibles dans quelques semaines).

    En attendant, comme indiqué par le journal et les autres commentaires, c'est tout à fait utilisable en choisissant les bonnes options. Je trouve juste étrange ce choix de faire un client officiel qui fait trop de choses, avec des options par défaut qui ne sont pas adaptées pour la prod (mais bon ils insistent bien sur le fait que c'est du beta).

  • # Ne pas utiliser le client

    Posté par . Évalué à 1.

    Moi je n'utilise pas le client letsencrypt sur mon serveur, je fais tout à la main, de la génération à la config de nginx, en utilisant ça : https://gethttpsforfree.com/

  • # Dépêche !

    Posté par . Évalué à 10.

    Moi, je vote pour une dépêche sur ce journal.

    Sinon, j'ai la flemme de le publier, mais j'ai fait un outil qui génère les enregistrements TLSA nécessaires pour DANE.
    Il suffit de passer en paramètres le nom du certificat ainsi que les ports (et oui, tout le monde ne fait pas du HTTP), et l'outil va lire le SubjectAlternativeName, et il fait son job. Ça intéresse des gens ?

    • [^] # Re: Dépêche !

      Posté par . Évalué à 3.

      Oui !

    • [^] # Re: Dépêche !

      Posté par . Évalué à 3.

      ca intéresse toujours :)

      mais en quoi est-ce bien différent de TLSA, le support des SAN ?
      Tu gères aussi le STARTTLS ? (ce qu'il manque à tlsa)

      Sinon j'avoue que letsencrypt je l'ai fait que pour un nom de domaine spécifique, accessible du publique, tout le reste je me base sur ma CA (a moi, reconnus par personne d'autre que moi).

      Le truc qu'il manque à letsencrypt c'est la possibilité d'avoir la clée en avance de phase (ou alors je ne l'ai pas vu de façon simple).
      La clé actuelle + la clée future (valide que dans le future). Comme ça pas de prise de tête avec DANE et les clés de backup. Surtout si il y a un script qui fait tout tout seul :)

      (parce que l'idée de changer de clé tous les 90 jours, honnêtement si on peut se le permettre, tant mieux).

      • [^] # Re: Dépêche !

        Posté par (page perso) . Évalué à 8.

        Le truc qu'il manque à letsencrypt c'est la possibilité d'avoir la clée en avance de phase (ou alors je ne l'ai pas vu de façon simple). La clé actuelle + la clée future (valide que dans le future).

        C’est possible à condition de gérer soi-même les clefs au lieu de laisser Letsencrypt en générer une nouvelle à chaque renouvellement.

        Ça implique de renoncer en partie à l’automatisation fournie par Let’s Encrypt, mais ça n’interdit pas d’automatiser soi-même. :)

        Surtout si il y a un script qui fait tout tout seul :)

        Un exemple à LA RACHE ? Un premier script new-key.sh pour gérer les rotations de clefs :

        #!/bin/bash
        
        keydir=keys
        
        if [ -f $keydir/server-key-next.pem ]; then
            # La prochaine clef existe déjà, on la promeut
            mv $keydir/server-key-next.pem $keydir/server-key.pem
        else
            # Pas de prochaine clef (première invocation?),
            # on génère une active
            openssl genrsa -out $keydir/server-key.pem 2048
        fi
        
        # On génère la nouvelle prochaine clef
        openssl genrsa -out $keydir/server-key-next.pem 2048
        
        # On génère les empreintes
        for key in $keydir/server-key{,-next}.pem ; do
            hpkp_pin=$(openssl rsa -in $key -pubout -outform DER 2>/dev/null | \
                openssl dgst -sha256 -binary | \
                openssl enc -base64)
            tlsa_pin=$(openssl rsa -in $key -pubout -outform DER 2>/dev/null | \
                openssl dgst -sha256 | cut -d' ' -f2)
            echo "HPKP: pin-sha256=\"$hpkp_pin\""
            echo "TLSA: 3 1 1 $tlsa_pin"
        done
        
        # On génère la demande de certificat
        # (cert.cfg contient les subjectAlternativeName)
        openssl req -new -key $keydir/server-key.pem \
            -config cert.cfg -outform DER -out cert.csr

        Un second script new-cert.sh demande un nouveau certificat :

        #!/bin/sh
        
        if [ ! -f cert.csr ]; then
            ./new-key.sh
        fi
        
        letsencrypt \
            certonly \
            --config ~/.config/letsencrypt/letsencrypt.conf \
            --csr cert.csr \
            --cert-path cert.pem \
            --chain-path chain.pem \
            --fullchain-path cert+chain.pem \
            --authenticator letsencrypt-ssh:ssh \
            --letsencrypt-ssh:ssh-server root@server.example.com \
            --domains $(openssl req -inform DER -in cert.xsr -noout -text | sed -nre 's/ +DNS://gp')

        Appeler le second script chaque fois qu’il faut renouveler le certificat ; appeler préalablement le premier script chaque fois qu’on veut changer de clef.

        Évidemment, le premier script peut faire quelque chose de plus intéressant que de simplement afficher les épingles. Par exemple, aller mettre à jour un fichier de zone.

        • [^] # Re: Dépêche !

          Posté par . Évalué à 2.

          Oui, alors justement, le roll-over (merci de m'indiquer un vrai mot français, je suis fatigué), c'est pas évident.

          Pour l'instant, le script que je fais ne fait que générer des enregistrements TLSA, mais j'ai déjà pensé à mettre un commentaire avec la date pour éviter d'effacer trop rapidement les enregistrements, en cas de lancement de script un peu trop… rapide.

          Dans le script façon LA RACHE, si la nouvelle clé vient tout juste d'être générée, les enregistrements HPKP et TLSA précédents n'auront pas vraiment eu le temps de se propager, ou d'expirer. Il faudrait un garde-fou pour ça :)

      • [^] # Re: Dépêche !

        Posté par . Évalué à 3.

        https://git.framasoft.org/Glandos/tlsa_from_x509

        C'est encore en travaux, et en plus, j'ai à peine le temps de bosser dessus. Mais c'est clairement quelque chose dont j'ai besoin, donc je ne vais pas l'abandonner.

        J'ai choisi de dépendre des binaires de openssl, parce que c'est difficile de faire un truc propre dans un langage de script sans dépendre de bibliothèques énormes, et que de toutes façons, openssl est déjà installé. Ce n'est pas un choix définitif :)

        • [^] # Re: Dépêche !

          Posté par (page perso) . Évalué à 4.

          C'est encore en travaux, et en plus, j'ai à peine le temps de bosser dessus. Mais c'est clairement quelque chose dont j'ai besoin, donc je ne vais pas l'abandonner.

          Tu en es probablement déjà conscient, mais je pense que le plus urgent à corriger est le fait que l’option --selector est ignorée : même avec --selector 1, ton script génère une empreinte sur le certificat entier et non sur la clef publique.

          Après, autoriser les noms du RFC 7218 à la place des valeurs numériques (par exemple --selector Cert au lieu de --selector 0, --usage DANE-TA au lieu de --usage 2, etc.) serait plus user-friendly.


          Pour l’intégration dans un fichier de zone, mon approche est la suivante : j’utilise un script qui se contente d’écrire l’empreinte sur sa sortie standard, et j’appelle ce script dans une macro M4 depuis mon fichier de zone. En quelque sorte c’est le fichier de zone qui va chercher la valeur dont il a besoin, plutôt que le script qui vient modifier le fichier de zone.

          Concrètement, j’ai ça dans mon fichier de zone :

          m4_define(SPKI_DIGEST, `m4_esyscmd(tls-key-mgmt spki-dgst -h $1)')
          
          […]
          
          _443._tcp.www.example.com.  IN  TLSA  3 1 1 SPKI_DIGEST(ee-web)
                                      IN  TLSA  3 1 1 SPKI_DIGEST(ee-web-next)
          

          tls-key-mgmt est mon script de gestion de clefs (appelé avec l’option spki-dgst, il renvoie l’empreinte de la clef publique spécifiée).

          J’utilise une approche similaire pour les enregistrements DKIM et OPENPGPKEY.

          Le fichier de zone est traité par M4 juste avant d’être envoyé à dnssec-signzone pour être signé.

          Ce que j’apprécie dans cette approche est que le script gérant les clefs et calculant les empreintes n’a pas besoin de savoir quoi que ce soit à propos du fichier de zone, son seul rôle est de sortir les empreintes sans se soucier de ce qu’elles deviennent ensuite.

          Cette indépendance me permet de réutiliser le même script pour insérer les empreintes dans le fichier de configuration d’Apache, pour la génération des en-têtes HPKP.

  • # Certificat sur un hébergement mutualisé

    Posté par . Évalué à 3.

    Est-il possible d'installer ce genre de certificat sur un hébergement mutualisé ?
    J'imagine que non mais je ne suis pas du tout au point dans ce domaine.

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.