Libricks

SSL Let's Encrypt Debian 8/9 &Ubuntu 16.04

Cette page va nous montrer comment créer un certificat SSL Let's Encrypt sous Debian 8 & 9 / Ubuntu 16.04 avec NGINX.

Prérequis :

Avoir un nom de domaine avec les enregistrements DNS pointant sur votre serveur
Un serveur web avec NGINX d'installer

Installation de Let's encrypt :

Pour pouvoir générer des certificats on va utiliser l'utilitaire Certbot qui est un outil proposé par l’EFF (Electronic Frontier Foundation) qui permet d’obtenir en une ligne de commande son certificat. On l'install avec la commande suivante :

sudo certbot --authenticator webroot --installer nginx

Génération du certificat :

Avant de créer à proprement dit les certificats SSL on va créer une nouvelle clé Diffie-Hellman (DH) de 4096 bits car SSL/TLS utilise un système de chiffrement asymétrique (comme RSA ou Diffie-Hellman) afin de sécuriser les échanges de vos flux. Par défaut, Nginx utilise une clé de 1048 bits. En augmentant la longueur de la clé à 4096 bits, vous augmenterez ainsi la sécurité de votre protocole SSL/TLS.

On génère donc une nouvelle clé Diffie-Hellman de 4096 bits et attribuez-lui un minimum de permissions :

sudo mkdir -p /etc/nginx/ssl
sudo openssl dhparam -out /etc/nginx/ssl/dhparam4.pem 4096
sudo chmod 600 /etc/nginx/ssl/dhparam4.pem

Cette étape peut prendre du temps relatif à la puissance de votre serveur

On génère un ticket que le serveur enverra au client, quand le client essaiera de se connecter à nouveau il utilisera le ticket et le serveur ne fera que reprendre la session. Nginx est livré avec les tickets de session activés par défaut mais si vous déployez votre application dans plus d'un serveur (bare metal, cloud, virtual machines, containers …), vous devrez également spécifier la même clé (utilisée pour créer les tickets).
Bien que cette approche soit bien meilleure que le cache de session, tous les navigateurs ne le supportent pas, vous pourriez donc avoir besoin d'offrir les deux solutions.

On génère donc la clé :

sudo openssl rand 48 -out /etc/nginx/ssl/ticket.key

Ensuite on génère le certificat pour votre nom de domaine avec la commande suivante :

certbot certonly --standalone -d monsite.fr

Si vous souhaitez générer un certificat pour plusieurs NDD par exemple monsite.fr et www.monsite.fr utiliser la commande suivante :

certbot certonly --standalone -d monsite.fr -d www.monsite.fr

Modification du vHost :

Voici comment modifier votre vHost NGINX pour qu'il redirige les requêtes HTTP vers HTTPS, ici le module HTTP2 est activé pour plus de sécurité & rapidité, celui-ci permet entre autres :

  • la compression des headers des requêtes et des réponses qui permet de réduire la bande passante lorsque les headers (comme les cookies) sont similaires
  • le multiplexage des requêtes au serveur consistant à faire passer de multiples informations via un seul tuyau de transmission. Ainsi, on économise les multiples connexions entre le client et le serveur. Les requêtes, quant à elles, sont effectuées simultanément par le navigateur. Les requêtes ne se suivent donc plus les unes derrière les autres (HTTP1) et les plus prioritaires (CSS par exemple) ne sont plus bloquées par les moins prioritaires (images par exemple)
  • Le push des ressources du serveur au navigateur. Désormais, le serveur pourra envoyer l’ensemble des ressources référencées dans une même page (CSS, JS…), avant même que le navigateur n’ait analysé celle-ci.

Veiller à remplacer les directives {votre_site} par votre nom de domaine dans le vHost

On ouvre le vHost à modifier :

vim /etc/nginx/sites-available/{votre_site}

On modifie donc le vHost de votre NDD par le contenu suivant :

# Redirection http vers https
server {
    listen 80;
    listen [::]:80; 
    server_name {votre_site}
    location / {
        return 301 https://{votre_site}$request_uri; 
    }
}
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    spdy_headers_comp 9;

    server_name {votre_site};
    root /var/www/{votre_site};
    index index.php;
    error_log /var/log/nginx/{votre_site}.log notice;
    access_log off;

    ####    Locations
    # On cache 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; }

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    ### Activation de PHP-FPM
    location ~ \.php(?:$|/) {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_param HTTPS on;
        fastcgi_param modHeadersAvailable true; #Avoid sending the security headers twice
        fastcgi_pass php-handler;
        fastcgi_intercept_errors on;
    }

    #### SSL
    ssl on;
    ssl_certificate /etc/letsencrypt/live/{votre_site}fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/{votre_site}privkey.pem;

    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_trusted_certificate /etc/letsencrypt/live/{votre_site}/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
    # Session Cache doit avoir la même valeur sur tous les blocs "server".
    ssl_session_cache shared:SSL:100m;
    ssl_session_timeout 24h;
    ssl_session_tickets on;
    ssl_session_ticket_key /etc/nginx/ssl/ticket.key;
    ssl_dhparam /etc/nginx/ssl/dhparam4.pem;

    ####    Rend le SSL plus sûr
    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';
}

On créer le lien symbolique qui va bien et on redémarre NGINX :

sudo ln -s /etc/nginx/sites-available/{votre_site} /etc/nginx/sites-enabled
sudo service nginx stop 
sudo service nginx start

Vérifier le certificat :

Vous pouvez tester la sécurité de votre certificat et du serveur NGINX grâce à se site : SSLlabs

Renouveler le certificat :

Pour renouveler vos certificats on utilisera un script exécuté par une tâche cron tout les X temps.
Donc dans votre contab :

sudo crontab -e

Placer y ceci à la fin :

30 2 * * 1 /usr/local/bin/letsencrypt-auto renew 1>/dev/null 2>&1

Ce qui éxécutera notre script placer dans /usr/local/bin tous les 7 jours à 2h30 du matin

Ensuite on créer un fichier pour notre script sudo vim /usr/local/bin/letsencrypt-auto

Et on y met le contenu suivant :

#!/bin/bash

if [ $# -lt 1 ]
then
  echo "Syntax error: $0 renew"
  exit 1
fi

do_renew() {
  SERVICE_HTTP=""
  SERVICE_HTTP=$(systemctl is-active nginx)

  if [ "${SERVICE_HTTP}" = "active" ]
  then
    systemctl stop nginx
    sleep 2
  fi

  certbot renew --dry-run
  certbot renew

  SERVICE_HTTP=""
  SERVICE_HTTP=$(systemctl is-active nginx)

  if [ "${SERVICE_HTTP}" != "active" ]
  then
    systemctl start nginx
    sleep 2
  fi
}

case "$1" in
  renew)
    do_renew
  ;;
  *)
    echo "Usage: $0 {renew}"
    exit 2
  ;;
esac

Conclusion

Voilà, vous avez votre certificat SSL Let's encrypt avec renouvellement automatique.
Si vous souhaitez plus d'informations sur l'utilisation de NGINX vous pouvez télécharger gratuitement le livre "The Complete NGINX Cookbook" sur le site de NGINX