NGINX et Let’sEncrypt

1.Configuration de Let’s Encrypt

Pour faire ce tutoriel, nous supposons que vous avez lu notre précédent article sur la configuration de NGINX. Votre serveur nginx doit être installé et fonctionnel. Maintenant que notre serveur web fonctionne correctement, nous pouvons essayer de faire des améliorations en sécurisant les échanges entre notre serveur et nos clients. Pour cela nous allons mettre en place du HTTPS. Au lieu d’acheter un certificat, nous allons utiliser ce petit projet gratuit, mais aussi  génial qu’est Let’s Encrypt. Il va nous permettre de créer des certificats automatiques et gratuits pour chacun de nos sites et nous pourrons même utiliser ses certificats pour sécuriser les sites pour lesquelles nous jouons le rôle de serveur proxy.

1.1 Installation du Client Certbot

Le nouveau client recommandé pour let’s Encrypt est Certbot. Nous allons commencer par l’installer sur notre système. Pour cela nous allons ajouter dans notre liste de dépôt (/etc/apt/source.list) si ce n’est pas déjà le cas le dépôt qui contient certbot. Nous sommes sur debian 8 (Jessie) donc si vous avez une autre version de linux ou une autre version de debian je vous invite a retrouver le dépôt qui a certbot (informations sur https://certbot.eff.org) ou alors d’utiliser un autre client.

Ouvrir le fichier avec :

nano /etc/apt/sources.list

Ajouter la ligne suivant à la fin du fichier :

deb http://ftp.debian.org/debian jessie-backports main non-free contrib
deb-src http://ftp.debian.org/debian jessie-backports main non-free contrib
deb http://ftp.debian.org/debian jessie main non-free contrib
deb-src http://ftp.debian.org/debian jessie main non-free contrib

Ensuite, mettez à jour la liste des paquets et installer certbot

apt update  &&  apt-get install certbot -t jessie-backports

Maintenant Certbot est installé. Certbot dispose d’un mode automatique qui va installer les dépendances nécessaires à l’outil et mettre en place les certificats en fonction de votre configuration serveur. Cette méthode d’installation automatique fonctionne  déjà très bien avec un le serveur web apache, mais reste à l’heure  actuelle (26/09/2016) expérimentale pour nginx (ce qui a peux être changé entre-temps). Il possède aussi le mode manuel. Dans ce cas, vous allez vous-même lancer la commande de génération de certificat pour chacun des sites que vous voulez passer en HTTPS et modifier vous-même les fichiers de configuration pour rediriger automatiquement les requêtes HTTP vers HTTPS.  Nous allons utiliser ce dernier mode.

1.2 Utilisation du client Certbot

1.2.1 Mode de fonctionnement et configuration

Pour générer nos certificats manuellement nous pouvons utiliser notre propre serveur web ou alors le serveur web interne à certbot.

  • Pour utiliser le serveur web interne à certbot, il est recommandé de couper momentanément notre serveur web personnel pour libérer le port 80 (pas très pratique si vous avez des sites qui tournent déjà et que vous ne voulez pas les interrompre). Dans ce cas on utilise la commande  certbot certonly –standalone -d example.com -d example.com
  • Pour utiliser notre propre serveur Web interne, nous allons faire appel aux plug-ins WebRoot. Afin de vérifier que vous êtes bien le possesseur du nom de domaine pour lequel vous souhaitez obtenir un certificat, Let’s Encrypt va générer un fichier sur votre serveur et va ensuite essayer d’y accéder depuis son serveur. Donc votre site web doit déjà être présent, fonctionnel et accessible de l’extérieur via le port 80. Cette configuration permet à Nginx d’avoir accès au répertoire .well-known/acme-challenge  afin de  créer les fichiers utiles à la validation de votre nom de domaine. Ajouter dans les configurations du site le contenu suivant  dans les balises server  { }.
# .well-known doit rester accessible pour que NGINX puisse le manipuler

    location ~ /\.well-known/acme-challenge {

        allow all;
    }

# On interdit habituellement l'accès au dotfiles (les fichiers cachés)

    location ~ /\. {

		deny all;

		access_log off;

		log_not_found off;

    }

NB : Quand vous souhaitez utiliser NGINX comme proxy vous devez vous aurez plutôt à ajouter ceux-ci dans le virtualhost. Dans la partie HTTP de la requête avant la redirection vers le https.

location ~ /.well-known/acme-challenge {

        root /var/www/html/;

        allow all;

}

1.2.2 Commande à utiliser

Pour utiliser chacune de ces méthodes vous avec le choix entre le mode interactif et le mode ligne de commande. Dans tous les cas noter que lorsque vous lancé la requête de demande de certificat avec let’s Encrypt, il vérifiera que le nom de domaine pour le qu’elle vous demandé un certificat correspond bien à l’adresse IP publique avec la qu’elle vous lancé la requête. IL faudra aussi se rassurer que le port 80 de votre IP public soit bien natté sur le serveur ou est installé le client Certbot.

  1. Pour appeler le mode interactif (graphique) utilisez la commande :
certbot certonly

Ensuite, suivez les indications données par l’interface et renseignez les informations qui vous sont demandées.

  1. Pour utiliser le mode commande, vous renseignez la commande suivante :
certbot certonly --email mon_adresse@google.com --webroot -w /var/www/exemple -d exemple.com -d www.exemple.com -w /var/www/thing -d truc.fr -d m.truc.fr

Explication:

L’option –w permet de spécifier le répertoire racine (répertoire root) du ou des noms de domaine qui sont spécifiés juste après avec l’option –d (les noms de domaine (-d) spécifié avant la prochaine option –w pointe tous sur le même site).

L’option –email permet de spécifier une adresse email. Elle n’est pas obligatoire, mais elle vous permet de recevoir un mail lorsque votre certificat approche de sa date d’expiration (très pratique tout ça).

Donc dans ce cas il va créer :

  • Un certificat pour le domaine example.com qui a aussi pour nom example.com et qui a pour répertoire Racine /var/www/exemple.
  • Un Certificat pour pour le domaine thing.is qui a aussi pour nom m.thing.is et qui a pour répertoire racine /var/www/thing.
  • La demande de renouvellement du certificat sera envoyée à l’adresse gkja2013@gmail.com

NB : Les certificats ne sont pas créés dans les répertoires racines des serveurs.  Ce répertoire est utilisé juste pour la création des fichiers de validation du nom de domaine qui sont supprimés par la suite. Les certificats et clés de let’sEncrypt se trouvent dans les répertoires :

/etc/letsencrypt/archive
/etc/letsencrypt/keys
/etc/letsencrypt/live
/etc/letsencrypt/renewal/

Les fichiers créés respectent à chaque fois la convention :

Dans le Dossier live :

Certificat principal :  /etc/letsencrypt/live/mon_domaine.fr/cert.pem
Chaine de certificats supplémentaires  :  /etc/letsencrypt/live/mon_domaine.fr/chain.pem
Certificat principale + Chaine de certificats supplémentaires :  /etc/letsencrypt/live/mon_domaine.fr/fullchain.pem
Clé privée du certificat  :  /etc/letsencrypt/live/mon_domaine.fr/privkey.pem

Dans le dossier Archive :

/etc/letsencrypt/archive/mon_domaine.fr/fullchain.pem
/etc/letsencrypt/archive/mon_domaine.fr/privkey.pem
/etc/letsencrypt/archive/mon_domaine.fr/chain.pem
/etc/letsencrypt/archive/mon_domaine.fr/cert.pem

Donc en tapant

 ls /etc/letsencrypt/live/

vous aurez la liste des Certificats (en réalité le dossier parent qui les contient).

Si la génération de certificat se passe correctement vous devez avoir le message suivant :

Qui vous confirme que la génération de certificat a bien été effectuée.

1.3 Création des paramètres de session et configuration du Virtual Host

1.3.1 Création des paramètres de session

Attention : La création de paramètres de session n’est à effectuer qu’une seule fois sur le serveur et sera utilisée pour tous les sites. Vous pouvez néanmoins le relancer si vous souhaitez renouveler les paramètres (attention aux sessions en cours).

Après avoir créé les certificats, vous devez générer les clés de session et le paramètre Diffie-Helman (sert crypter le premier échange entre le serveur et le client).  Ceux-ci n’est pas obligatoires, mais permet d’accroitre la sécurité (si vous ne l’utilisez pas pour une raison ou pour une autre pensez à supprimer les lignes correspondantes dans le fichier de configuration). Nous allons créer un répertoire nommé ssl dans le répertoire de configuration de NGINX pour y générer ces fichiers.

sudo mkdir /etc/nginx/ssl
sudo openssl rand 48 -out /etc/nginx/ssl/ticket.key
sudo openssl dhparam -out /etc/nginx/ssl/dhparam4.pem 4096

NB: La dernière commande (celle qui génère le paramètre Diffie-Helman) prend beaucoup de temps vu que j’ai spécifié une clé de 4096 pour un max de sécurité. Donc, soyez très patient. Bon la vitesse dépendra aussi un peu de votre configuration.

1.3.2 Configuration du Virtual Host

Modifier ensuite votre Virtual host (le fichier de configuration du site) comme celui-ci en adaptant les configurations. Pensez à modifier mon_domaine.fr par le nom de votre domaine et /var/www/html  par le répertoire racine de votre site web. Ou alors, adaptez-le comme il faut pour un serveur proxy.

  • Pour un Site web:
# Redirection HTTP vers HTTPS

server {

        listen 80;

        # Vous pouvez en mettre plusieurs à la suite, Bien sûr faudrait qu’il ait été spécifié dans le certificat
        server_name mon_domaine.fr www.mon_domaine.fr;

  		location ~ /.well-known/acme-challenge {

        	root /var/www/html/;
        	allow all;

        }


		location / {

              return 301 https://www.mon_domaine.fr$request_uri;

        }

}



# Notre bloc serveur

server {

    # spdy pour Nginx < 1.9.5

    listen 443 ssl spdy;

    listen [::]:443 ssl spdy;

    spdy_headers_comp 9;


    server_name mon_domaine.fr www.mon_domaine.fr;
    root /var/www/html;
    index index.html index.htm;
    error_log /var/log/nginx/mon_domaine.fr.log notice;
    access_log off;


    ####    Locations

    # Si On veut cacher les fichiers statiques

    # location ~* \.(html|css|js|png|jpg|jpeg|gif|ico|svg|eot|woff|ttf)$ { expires max; }

    # On interdit les dotfiles

    location ~ /\. { deny all; }


    #### SSL

    ssl on;
    ssl_certificate /etc/letsencrypt/live/mon_domaine.fr/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/mon_domaine.fr/privkey.pem;



    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_trusted_certificate /etc/letsencrypt/live/mon_domaine.fr/fullchain.pem;

    # Google DNS, Open DNS, Dyn DNS

    resolver 8.8.8.8 8.8.4.4 208.67.222.222 208.67.220.220 216.146.35.35 216.146.36.36 valid=300s;
    resolver_timeout 3s;



     ####    Session Tickets

    # [ATTENTION] Session Cache doit avoir la même valeur sur tous les blocs "server" et doivent être générés.

    ssl_session_cache shared:SSL:100m;
    ssl_session_timeout 24h;
    ssl_session_tickets on;

    # [ATTENTION] il faudra générer le ticket de session.

    ssl_session_ticket_key /etc/nginx/ssl/ticket.key;


    # [ATTENTION] Les paramètres Diffie-Helman doivent être générés

    ssl_dhparam /etc/nginx/ssl/dhparam4.pem;


    ####    ECDH Curve

    ssl_ecdh_curve secp384r1;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK';



}

Pensez vérifier que les configurations de nginx sont correctes avec :

nginx -t 

avant de faire un reload des configurations du serveur pour éviter de le faire cracher.  Si tous est OK vous aurez  le message suivant :

Si tout est OK faite un :

services nginx reload     

ou

 systemctl reload nginx

Vous pouvez aussi écrire un script qui fait cela tout seul. Vous lui passez juste en paramètre les noms de domaines et les chemins racines souhaités pour les sites et lui il s’occupe du reste. Le script peut également faire toute les vérifications nécessaires.

  • Pour un site proxy :

Adapter les configurations précédemment utilisées pour le site web, pensez surtout à commenter ou a supprimer les 4 lignes suivantes :

  root /var/www/html;
  
  index index.html index.htm;
  
  error_log /var/log/nginx/ mon_domaine.fr.log notice;
  
  access_log off;

Et à les remplacer par les lignes suivantes en remplaçant http://127.0.01:3000  par l’adresse IP réelle et le port (l’adresse complète) du site vers lequel vous souhaitez pointer. Si  vous souhaitez accéder à un site en local utilisé plutôt localhost au lieu de 127.0.0.1.

     location / {

                proxy_pass         http://127.0.0.1:3000/;
                }

Vous avez surement remarqué que j’utilise ici HTTP au lieu de HTTPS en fait, je suppose, ici que c’est votre serveur proxy qui héberge le certificat SSL. Vous pouvez adapter les configurations en fonction de votre architecture.

  • Pour le site maitre :

C’est celui qui va être appelé par défaut si les autres sont indisponibles ou celui qui sera retourné tant que le nom de domaine pointe sur le serveur et n’est pas défini explicitement dans un virtual host(pour un Site). Cette configuration n’est pas absolument nécessaire. Vous la mettez en place sur un site si vous le souhaitez. Vous pouvez aussi  tous simplement laisser le visiteur tomber sur une page d’erreur au cas où il tape mal l’adresse de l’un de vos sites. Cette option est particulièrement intéressante si vous avez référencé tous les sites que vous hébergez sur une page.

NB : Il ne peut y avoir qu’un seul site maitre sur un serveur NGINX.

  • Ajouter simplement sur la ligne listen 80 ; de la configuration par défaut d’un site web le mot clé default_server. Vous aurez ceux-ci :   listen 80 default_server;
  • Et mettez le tild (_) comme nom de serveur : server_name _ ;
  • Vérifier vos configurations :

Une fois que le SSL a été mis en place pour tester la robustesse de votre système il vous suffit de coller l’adresse de votre site ici. Se site testera si votre configuration respecte tous les principes de sécurité, car malgré l’utilisation du SSL si votre configuration est mal faite, il y aura des portes ouvertes pour les hackers.

1.4 Renouvellement du Certificat

Les certificats Let’sEncrypt ne sont valables que pendant 90 jours (3 mois).  Donc il est très facile d’oublier de les renouveler. La commande suivante renouvelle les certificats sans interaction de votre part. Cette commande ne fera rien si le certificat n’a pas encore besoin d’être renouvelé:

certbot renew

Si cela fonctionne correctement vous pouvez ajouter une entrée a la cron table ou job systemd pour faire cela automatiquement.

Le job se lance avec la commande :

certbot renew -q

La cron table nous permettra d’exécuter une tâche de manière récurrente :

sudo crontab -e

Ensuite, choisissez votre éditeur si c’est la première fois que vous utilisez crontab et qu’il vous le demande. Entrer les lignes suivantes.

La syntaxe des lignes de ce fichier est la suivante :  mm hh jj MMM JJJ tâche > log

mm : représente les minutes (de 0 à 59)

 hh : représente l’heure (de 0 à 23),

 jj : représente le numéro du jour du mois (de 1 à 31)

MMM : représente le numéro du mois (de 1 à 12) ou l’abréviation du nom du mois (jan, feb, mar, apr, …)

JJJ : représente l’abréviation du nom du jour ou le chiffre correspondant au jour de la semaine (0 représente le dimanche, 1 représente le lundi, …)

Tâche : représente la commande ou le script shell à exécuter

log : représente le nom d’un fichier dans lequel stocker le journal des opérations. Si la clause > log n’est pas spécifiée, cron enverra automatiquement un mail de confirmation. Pour éviter cela il suffit de spécifier > /dev/null.

Ex : tous les 23h30 :   30 23 * * * df >>/tmp/log_df.txt

Ajoutez les lignes suivantes dans votre cron table :

25 2 * * * date >> /var/log/certbot-renew.log

30 2 * * * certbot renew -q >> /var/log/certbot-renew.log

25 12 * * * date >> /var/log/certbot-renew.log

30 12 * * * certbot renew -q >> /var/log/certbot-renew.log

Si nginx a du mal à prendre en compte le nouveau certificat vous pouvez rajouter la ligne suivante :

35 2 * * * service nginx reload

NB : Si vous ajoutez la commande a la cron table ou à systemd, il est conseillé mettre une tâche récurrente qui se lance 2 fois par jour afin de rester actif auprès de let’sEncrypt . Cela vous permet de réduire les risques que votre certificat soit révoqué parce qu’arrivé à expiration ou pour une raison quelconque. De toutes les façons si le certificat n’a pas besoin d’être renouvelé, la commande ne fera rien.

1.5 Révocation de certificat

Si pour une raison ou une autre vous voulez révoquer votre certificat par exemple si votre clé privée a été corrompue, vous pouvez essayer la commande suivante :

certbot revoke --cert-path /etc/letsencrypt/live/mon_site.fr/cert.pem

Dans mon cas généralement elle ne renvoie aucune erreur et par moment elle renvoie une erreur (là je suppose qu’en même qu’elle a bien fonctionné). Mais peut-être a-t-elle été mise à jour entre temps. J’ai parfois l’erreur suivante alors que je lance la commande de suppression d’un certificat  d’un sous domaine pour la première fois.

An unexpected error occurred:
The request message was malformed :: Certificate already revoked
Please see the logfiles in /var/log/letsencrypt for more details.

Dans tous les cas une fois que cette commande a été exécutée pensez à supprimer les fichiers de l’ancien certificat :

rm  -r /etc/letsencrypt/live/mon_site.fr
rm -r /etc/letsencrypt/archive/mon_site.fr
rm /etc/letsencrypt/renewal/mon_site.fr.conf

NB : Je ne suis pas sûr que c’est très propre. Mais bon cela a le mérite de fonctionner.

Pour vérifier que votre certificat a bien été retiré de la liste de vos certificats, lancer la commande certbot renew. Elle vérifiera chacun de vos certificats et vous les affichera. Vous pouvez constater que le certificat qui a été révoqué et supprimé de la liste de vos certificats n’y est plus.

Si vous relancer la commande de création de certificats avec le même nom de domaine que vous avez précédemment révoqué vous pouvez constater que  le certificat est créé de nouveau et que la date d’expiration est différente du précédent certificat elle est calculée  à partir de la date à laquelle vous avez ressaisi la commande de création de certificats.

2.    Webographie

G33keries.org 

ZCFY (en anglais)

8 réflexions au sujet de « NGINX et Let’sEncrypt »

  1. Excellent article, simple à lire et sans informations superflues.

    Juste un détail concernant le fonctionnement de Let’s Encrypt: lorsque notre serveur demande un certificat pour un ensemble de noms de domaines, « LE » vérifiera si l’IP publique depuis laquelle est faite la demande correspond à ces noms de domaine. De plus, le challenge que lance « LE » vers notre répertoire /.well-known/acme-challenge se fait uniquement sur le port 80!
    Pour résumer il serait intéressant de préciser que les noms de domaine concernés par notre requête doivent (tous) correspondre à notre adresse IP publique et que le port 80 (entrant) doit être ouvert et NATé vers notre serveur.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *