Installer un certificat Let's Encrypt

ssl-certif

Ça fait une paie que je n’ai pas sorti un truc un peu plus geek, mais je me suis dit que ça pourrait me faire un pense-bête si je vous expliquais un peu comment j’ai fini par mettre en place ma demande de certificat Let’s Encrypt. Pour ceux que ça intéresse, ça fera un début et ça passera le temps en attendant que ça sorte de beta.

Une paire de choses d’abord : Je vise ici ceux qui bidouillent. Let’s Encrypt fournit un client pour tout faire à votre place qui vous conviendra peut-être, mais il doit avoir tous les droits sur votre serveur, c’est difficile de comprendre exactement ce qu’il fait, et moi j’aime bien comprendre ce qui se passe. comme en plus mes serveurs sont parfois bizarres, j’opte pour une procédure plus manuelle.

Je pose comme pré-requis que vous savez configurer votre serveur Apache/Nginx/autre. Je donnerai quelques exemples sur une config Apache, qui est ce que j’ai utilisé. Oui, ça veux dire mettre les mains dans le cambouis, mais ce n’est pas par manque de désir de simplifications : il FAUT modifier la config du serveur pour installer un certificat. De toutes façons, je parle de l’obtention/renouvellement du certificat, avec juste un minimum sur la config du serveur ensuite.

Vous aurez besoin :

  • d’une clef privée pour vous identifier.
  • d’une clef privée pour identifier le serveur.
  • d’une demande de certificat pour votre (vos) domaine(s).
  • d’une copie du certificat de Let’s Encrypt

Je vais donner des noms significatifs aux fichiers, mais vous donnez les noms que vous voulez.

Création des clefs privées

openssl genrsa 4096 > clef_privee_perso.key

openssl genrsa 4096 > clef_privee_machine.key

C’est à peu près tout. La première servira d’identifiant chez Let’s Encrypt. La seconde servira à signer votre demande de certificat, et ensuite à vérifier lors de son utilisation qu’on est sur la bonne machine.

Règle d’hygiène de base en matière de clefs : elles sont super importantes. Ne les perdez pas, ne les laissez pas traîner à un endroit où elles seraient accessibles à tout le monde.

Création de la demande de certificat

Vous allez créer un Certificate Signing Request (CSR) pour dialoguer avec Let’s Encrypt. Voyez ça comme un formulaire à remplir. Double avantage : il n’y a pas de risque d’incompréhension, et surtout le même formulaire servira pour -et on verra l’intérêt- le renouvellement (la commande est en un seule ligne) :

openssl req -new -sha256 -key clef_privee_machine.key -subj “/” -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf “[SAN]\nsubjectAltName=DNS:tonsite.com,DNS:www.tonsite.com”)) > formulaire_de_demande.csr[1]

Il y a une façon légèrement plus simple de faire si on n’a qu’un domaine[2], mais si on a le www, ou d’autres sous domaines, il vaut mieux tout faire d’un coup. Remplacez ce qu’il faut dans la ligne au dessus par DNS:url.du.site.com, séparés par des virgules, et sans espace[3].

Certificat intermédiaire

Souvent ça marchera sans, mais il peut y avoir un avertissement en fonction de la configuration. Il est donc préférable d’avoir sur son serveur une copie du certificat de Let’s Encrypt, histoire d’éviter à votre machine d’aller le chercher à chaque fois qu’elle en a besoin. Il est là :

https://letsencrypt.org/certs/lets-encrypt-x1-cross-signed.pem

Préparation du serveur

Lorsque vous faites la demande de certificat, il y a un dialogue entre Let’s Encrypt et votre serveur. En gros, vous donnez le formulaire avec la liste des domaines pour lesquels vous voulez un certificat, et pour chaque, Let’s Encrypt vous envoie un jeton (token) qui doit être accessible sur votre site web à une adresse précise avant que la transaction continue, c’est pour prouver qu’il s’agit bien de votre domaine.

Vous devez préparer à l’avance le répertoire où déposer ces jetons. Il doit être accessible à l’adresse suivante sur votre site : http://tonsite/.well-known/acme-challenge/

Demande de certificat

Let’s Encrypt a fourni un client pour ça, mais j’ai trouvé le truc un peu lourdingue à mon goût. En fouillant un peu, je suis tombé sur plusieurs autres solutions dont ça : acme_tiny. Ça fait moins de 200 lignes, c’est facile à auditer, et ça ne demande pas de droits bizarres[4], c’est vous qui vous débrouillez derrière. La commande est simple (et est également en un seule ligne) :

python acme_tiny.py —account-key ./clef_privee_perso.key —csr ./formulaire_de_demande.csr —acme-dir /var/www/site/.well-known/acme-challenge/ > ./certificat-domaines.pem

(ce qu’il y a derrière acme-dir, c’est évidemment le répertoire qui sera accessible publiquement)

Si tout se passe bien, le script va initier le dialogue avec Let’s Encrypt, recevoir les jetons, les créer dans le répertoire, vérifier qu’ils sont accessibles par http, prévenir Let’s Encrypt qu’il peut vérifier et signer le certificat, et supprimer les jetons quand il a fini.

Installation du certificat

Un fois que vous avez le certificat, il suffit de créer des vhosts sur le port 443 dans votre serveur web, pour lequel vous devez indiquer le chemin du certificat, de celui de Let’s Encrypt que vous avez téléchargé plus tôt, et de la clef privée du serveur. Un exemple minimal sous Apache, avec un exemple des chemins pour les différents fichiers[5] :

<VirtualHost *:443>
    ServerName tonsite.net
    ServerAlias www.tonsite.net
    
    SSLEngine on
    SSLCertificateFile /etc/ssl/certs/certificat-domaines.pem
    SSLCertificateChainFile /etc/ssl/certs/lets-encrypt-x1-cross-signed.pem
    SSLCertificateKeyFile /etc/ssl/private/clef_privee_machine.key
    
    DocumentRoot /var/www/
</VirtualHost>

Notez que de ce que je sais, il n’y a pas d’équivalent à SSLCertificateChainFile sur Nginx, il faut concaténer la chaîne des certificats et fournir celle-ci :

cat certificat-domaines.pem lets-encrypt-x1-cross-signed.pem > certificat-complet-a-utiliser.pem

Renouvellement du certificat

Un petit détail à connaître sur les certificats Let’s Encrypt : ils ont une durée de vie de trois mois. On aura donc tout intérêt à simplifier la procédure, parce que sinon, ça risque d’être un peu lourd très vite. La bonne nouvelle, c’est que vous pouvez tout simplement réutiliser le même formulaire à chaque fois. Si vous avez suivi les instructions ci-dessus, il suffit de relancer exactement la même ligne de commande qu’à la rubrique “demande de certificat”. C’est facile à ranger dans un cron, par exemple.

Et puis après ?

Après, tout ça est une base de travail. Ça peut fonctionner simplement comme ça, ou vous pouvez être psychop^H^H^H^H^H^H^H^H perfectionniste en gérant vos répertoires par alias, en les rendant inaccessibles pour qui ne sait pas le nom des jetons, en faisant des redirections vers un (sous) domaines spécialisé (ça marche), en redirigeant vos pages vers la version sécurisée, et surtout en bidouillant la config ssl aux petits oignons pour plus de sécurité (et avoir une bonne note chez ssllabs), mais nous ne sommes ici que pour les briques de base.

Voilà. C’est du pense-bête pour moi, donc je ne sais pas si c’est clair. On peut en discuter, je peux même faire des modifs, si c’est nécessaire. Lâche tes coms.

Notes

[1] Je pourrais expliquer exactement cette commande, mais il faudrait un autre billet. Il y a d’autres façons de faire, que je fouille.

[2] Pour être complet : openssl req -new -sha256 -key domain.key -subj “/CN=tonsite.com” > formulaire_de_demande.csr

[3] Attention, pendant la béta de Let’s Encrypt, on n’a droit qu’à cinq certificats par domaine (sous domaines inclus) par semaine. Pour le moment, je ne peux plus rien tester : j’ai dépassé mes quotas.

[4] Added bonus : les exemples qu’ils donnent, eux, sont pour Nginx, pour ceux que ça intéresse.

[5] Je suis preneur de toute commentaire quant à la pertinence de ces chemins)

Commentaires

1. Le jeudi 10 décembre 2015, 16:18 par doublenain

Enfin une vraie doc, très claire.

Parce-que celle fournie par Let's Encrypt est pourrie ! J'ai failli abandonner !

Encore merci à vous !

2. Le jeudi 10 décembre 2015, 16:23 par xave

Ah, c'est cool, merci. J'avais vraiment peur d'avoir l'air de vouloir me rendre intéressant avec un truc que personne n'allait trouver utile. Si ça peut servir à quelques-un, c'est déjà très bien.

3. Le jeudi 10 décembre 2015, 16:33 par doublenain

Tu dois garder confiance en toi...Ton blog est bien, je me suis même abonné à ton flux RSS.

Ceux qui méritent l'intérêt sont ceux qui partagent la connaissance pas les acteurs, footeux ou hommes mafieux politiques dont les paroles sont de plus en plus vides de sens et qui pour le coup sont eux de véritables imposteurs ;)

4. Le samedi 12 décembre 2015, 23:31 par maggick

Super billet, très clair !

Par contre dans la configuration apache ça ne serait pas :
SSLCertificateKeyFile /etc/ssl/private/clef_privee_machine.key
plutôt que
SSLCertificateKeyFile /etc/ssl/private/clef_privee_perso.key
?

5. Le dimanche 13 décembre 2015, 11:36 par xave

Ah merde, bien vu ! Je corrige de suite. Tu as gagné un certificat gratuit.

6. Le mercredi 16 décembre 2015, 02:04 par Adrien

Très bonne article !

Pour ma part j'ai tenté de l'installer sur mon serveur sans succès. J'ai des problème de dépendances avec la version de python.

La chose très chouette c'est que des grands hébergeurs francophone comme infomaniak (https://news.infomaniak.com/certifi...) ou PlanetHoster (https://blog.planethoster.net/exclu...)prennent le train en marche.

Ayant un plan chez PlanetHoster je vous confirme que cela est déjà en place et fonctionne très bien !

A bientôt !

7. Le jeudi 24 décembre 2015, 12:11 par stombi

Merci excellent article, la procédure m'a pris 10 minutes maxi.
Juste un petit bémol, la ligne de commande avec acme_tiny.py les -- sont remplacés par un tiret long (le copier/coller m'a tuer) ;-)

8. Le lundi 26 septembre 2016, 17:12 par unknown

bonjour, j'ai l'erreur suivante:

root@locationvps:/root/ssl# python acme_tiny.py .account-key ./clef_privee_perso.key .csr ./formulaire_de_demande.csr .acme-dir /var/www/mail/.well-known/acme-challenge/ > ./certificat-domaines.pem
usage: acme_tiny.py -h account-key ACCOUNT_KEY csr CSR --acme-dir
ACME_DIR --quiet --ca CA
acme_tiny.py: error: argument --account-key is required

alors que si je vais un ls:
root@locationvps:/root/ssl# ls
LICENSE acme_tiny.py certificat-domaines.pemcsr clef_privee_perso.key lets-encrypt-x1-cross-signed.pem
README.md certificat-domaines.pem clef_privee_machine.key formulaire_de_demande.csr tests
root@locationvps:/root/ssl#

tout a l'air d'être bon pourtant mais ça ne marche pas.

9. Le lundi 26 septembre 2016, 17:21 par xave

Un problème de mauvais caractère pour les arguments, peut-être bien : c'est acme_tiny.py <tiret><tiret>account-key

10. Le mardi 27 septembre 2016, 10:27 par unknown

Merci, Effectivement c’était bien les "—" et non "--" qui poser problème, en revanche j'ai un autre soucis, ou configurer le virtual host pour apache2 car moi quand je le met dans /etc/apache2/sites-enabled/000-default.conf j’obtiens une erreur:

root@locationvps:/etc/apache2/sites-enabled# /etc/init.d/apache2 restart
.... Restarting apache2 (via systemctl): apache2.serviceJob for apache2.service failed. See 'systemctl status apache2.service' and 'journalctl -xn' for details.
failed!

j'ai essayer de le mettre dans le: sites-available/default-ssl.conf

mais quand je vais sur le https:// je suis constamment rediriger sur le http://

11. Le mardi 27 septembre 2016, 10:47 par xave

Là, on arrive à une erreur spécifique à la config, donc je ne peux pas faire grand-chose. À part penser que mettre du certificat nominatif, valable pour un un seul hostname, dans le default.conf d'Apache, ce n'est peut-être pas la configuration idéale.

12. Le mardi 27 septembre 2016, 12:17 par unknown

c'est la config de base sur debian 8.6

13. Le mardi 27 septembre 2016, 15:41 par unknown

J'ai finalement réussi en configurant:

<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerAdmin contact@*****.ec

ServerName ****.com
DocumentRoot /var/www/mail/
<Directory />
Options FollowSymLinks
AllowOverride None
</Directory>
<Directory /var/www/mail/>
Options Indexes FollowSymLinks MultiViews
AllowOverride None
Order allow,deny
allow from all
</Directory>

SSLCertificateFile /var/www/ssl/certificat-domaines.pem
SSLCertificateKeyFile /var/www/ssl/clef_privee_machine.key

</VirtualHost>
</IfModule>

directement dans le default-ssl, merci encore pour tes réponses.

14. Le mardi 27 septembre 2016, 15:45 par unknown

je précise aussi que j'ai dû utiliser la commande: a2ensite default-ssl.conf pour l'activer et ensuite recharger apache2, la commande a2dissite default-ssl.conf peut aussi être pratique quand la config est mauvaise et plante l'apache2.

et que le fichier est dans /etc/apache2/sites-availabe et non dans sites-enabled

15. Le jeudi 29 septembre 2016, 10:45 par unkown

salut xave, tu pourrais nous dire comment obtenir la note A+ ? quels directive as tu mis dans la config d'apache (vhost ssl) car j'arrive tous juste la note A et non A+

Merci d'avance :)

16. Le mercredi 3 mai 2017, 10:48 par Pinkilla

merci pour la doc.

tu fonctionnes toujours comme ça aujourd'hui ou ça a évolué en 2017 ?

17. Le mercredi 3 mai 2017, 19:11 par xave

Toujours pareil, je n'ai eu aucune raison de changer : ça tourne, et j'ai juste un script qui va renouveler régulièrement les certificats.

18. Le samedi 17 juin 2017, 23:33 par Mathieu

Bonsoir,

j'avais ce lien dans mes favoris depuis un moment et je me décide enfin à passer mon serveur en https

et du coup je rencontre un blocage à ce moment :
openssl req -new -sha256 -key clef_privee_machine.key -subj “/” -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf “SAN\nsubjectAltName=DNS:monsite.fr,DNS:www.monsite.fr”)) > formulaire_de_demande.csr

il me sort ce message
error on line 351 of /dev/fd/63
139778323134112:error:0E079065:configuration file routines:DEF_LOAD_BIO:missing equal sign:conf_def.c:351:line 351

Une idée de ce qui peut bloquer ?
Par avance merci :)

19. Le dimanche 18 juin 2017, 10:55 par xave

Alors, à vue de nez, comme ça, non. Ou alors juste une petite : si tu ne l'as pas fait, essaie un peu de remplacer les guillemets que tu copie-colles par des guillemets normaux.

20. Le dimanche 18 juin 2017, 11:58 par Mathieu

Effectivement ça venait des guillemets merci :)

Page top