Générer un certificat TLS pour sécuriser son réseau interne

Il arrive que l'on souhaite sécuriser les échanges entre les services de notre réseau interne. Pour cela, il faut générer deux certificats. Le premire devra être installer sur le poste du client et le second sur le serveur.

Dans cet article, vous découvrirez comment générer ces 2 certificats et comment les installer dans un conteneur LXC sous Debian 11 (Bullseye) avec Nginx. La génération des certificats est réalisée par OpenSSL.

Pré-requis

J'utilise Proxmox pour déployer mon conteneur que j'ai nommé nginx.poc.tls. J'ai également installé curl et nginx. Sous Proxmox, le host étant identique au nom du conteneur, j'ai exécuté la commande curl http://nginx.poc.tls pour vérifier que Nginx est bien installé et exécuté.

Le retour de cette commande est la suivante :

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

C'est parfait, le service Nginx est fonctionnel. Relançons la même commande, avec https au lieu de http, voici le résultat :

curl: (7) Failed to connect to nginx.poc.tls port 443: Connection refused

Avant de modifier les fichiers de configuration de Nginx pour lui indiquer qu'il faut écouter sur le port 443. Nous allons créer le certificat.

Certificat TLS

Le certificat sera créé par OpenSSL. Je vous invite à lancer la commande openssl version pour vérifier qu'OpenSSL est bien installé.

Lien vers la documentation de la commande OpenSSL.

Création de l'autorité de certification

Pour cette première partie, nous allons utilisé 2 commandes openssl genpkey et openssl req.

Commençons par générer la clé de notre certicat d'autorité en lançant la commande suivante. une passphrase vous sera demandé lors de l'exécution :

openssl genpkey -algorithm RSA -aes-256-cbc -out ca-key.pem

La commande openssl genpkey remplace openssl genrsa. Nous lui indiquons que nous souhaitons générer une clé privée RSA avec l'aide de l'algorithme de chiffrement symétrique AES-256-CBC. Notre clé sera enregistrée dans le fichier ca-key.pem.

Nous allons ensuite généré un certificat public en exécutant la commande :

<!-- openssl req -new -x509 -days 180 -sha512 -key ca-key.pem -out ca.pem -->

Cette commande est composée de plusieurs options, voici quelques précisions à leur sujet :

  • -new précise que la commande est une nouvelle demande.
  • -x509 génère un certificat auto-signé au lieu d'une demande de certificat.
  • -days permet de préciser la durée de vie du certificat, dans notre cas 180 jours, par défaut la valeur est de 30 jours.
  • -sha512 spécifie comment signer la demande
  • -key ca-key.pem indique à la commande la clé à utiliser, soit la clé précédemment générée
  • -out ca.pem indiquer le fichier de sortie

Une fois lancée, la passphrase vous sera demandée et quelques questions vous serons posées. Les réponses aux questions seront présentes dans le certicat généré.

Voici les liens vers la documentation des 2 commandes utilisées :

Création du certificat

Nous aurons besoin d'exécuter 4 commandes pour créer notre certificat en commençant par la génération d'une nouvelle clé en réutilisant la commande openssl genpkey avec les mêmes paramètres sauf que le fichier de sortie est différent.

Les noms des fichiers de certificat sont génériques, je vous invite à les modifier.

openssl genpkey -algorithm RSA -aes-256-cbc -out certificat-key.pem

Puis, nous allons générer une demande de signature de certificat, généralement appelé CSR pour Certificate Signing Request.

openssl req -new -sha512 -subj "/CN=nginx-poc-tls" -key certificat-key.pem -out certificat.csr

La commande est quasiment identique à celle permettant de générer un certificat public. L'option -subj "/CN=nginx-poc-ssl" définit le sujet de notre nouvelle demande. Vous êtes libre d'indiquer ce que vous souhaitez.

Nous allons désormais créer un fichier de configuration qui stockera les informations DNS ainsi que l'adresse IP de notre certificat. Avant de lancer la commande, je vous invite à récupérer l'adresse IP de votre conteneur Nginx, en utilisant la commande ip a.

echo "subjectAltName=DNS:nginx.poc.tls,IP:10.255.89.139" >> config-file.conf

La dernière étape consiste à créer le certificat à partir des différents fichiers que nous avons générés précédemment :

openssl x509 -req -sha512 -days 180 -in certificat.csr -CA ca.pem -CAkey ca-key.pem -out certificat.pem -extfile config-file.conf -CAcreateserial

Voici quelques précisions sur les options la commande openssl x509 :

  • -req est utilisée pour indiquer que l'on va faire une demande de certificat
  • -sha512 précise que l'on souhaite utiliser sha512 pour signer le certificat, par défaut sha1 est utilisé
  • -days 180 indique le nombre de jours pour la validité du certifcat, par défaut la valeur est 30 jours
  • -in certificat.csr spécifie le fichier d'entrée
  • -CA ca.pem précise l'autorité de certificat qui sera utilisé pour la signature
  • -CAkey ca-key.pem préciser la clé de l'autorité de certificat
  • -out certificat.pem indique le nom du fichier du certificat que l'on souhaite générer
  • -extfile config-file.conf spécifie le fichier de configuration contenant les extensions à utiliser
  • -CAcreateserial indique que le numéro de série du certificat doit être créé

Lien vers la documentation de la commande openssl x509

Configuration de Nginx

Maintenant que nos certificats sont créés, nous allons configurer Nginx. Mais avant, nous allons copier les fichiers du certificat dans le dossier etc\ssl\ :

cp certificat.pem /etc/ssl/.
cp certificat-key.pem /etc/ssl/.

Avant de modifier la configuration de Nginx, nous devons créer un fichier contenant la passphrase du certificat, vous pouvez créer le dossier /etc/keys ains que le fichier certificat.keys :

mkdir /etc/keys
echo "<ma-passphrase>" > /etc/keys/certificat.keys

Désormais, nous allons pouvoir modifier la configuration de Nginx pour lui indiquer d'écouter sur le port 443 et d'activer les certificats que nous avons créés. Pour ce faire, nous allons éditer le vhost default, qui se trouve dans le dossier /etc/nginx/sites-available.

Ce fichier comporte 1 directive server que nous allons modifier :

server {
    listen 80 default_server;
    listen [::]:80 default_server;

    # SSL configuration
    #
    # listen 443 ssl default_server;
    # listen [::]:443 ssl default_server;
    #
    # Note: You should disable gzip for SSL traffic.
    # See: https://bugs.debian.org/773332
    #
    # Read up on ssl_ciphers to ensure a secure configuration.
    # See: https://bugs.debian.org/765782
    #
    # Self signed certs generated by the ssl-cert package
    # Don't use them in a production server!
    #
    # include snippets/snakeoil.conf;

    root /var/www/html;

    # Add index.php to the list if you are using PHP
    index index.html index.htm index.nginx-debian.html;

    server_name _;

    location / {
        # First attempt to serve request as file, then
        # as directory, then fall back to displaying a 404.
        try_files $uri $uri/ =404;
    }
}

Nous allons modifier cette instruction en commentant les 2 lignes ci-dessous :

listen 80 default_server;
listen [::]:80 default_server;

Puis, nous décommettons les 2 ci-dessous :

listen 443 ssl default_server;
listen [::]:443 ssl default_server;

Pour terminer, nous devons ajouter les lignes :

ssl_certificate /etc/ssl/certificat.pem;
ssl_certificate_key /etc/ssl/certificat-key.pem;
ssl_password_file /etc/keys/certificat.keys;

Quittons nano, puis réalisons un test de configuration de Nginx :

/usr/sbin/nginx -t

Si la configuration à été vérifiée avec succès, vous pouvez relancer Nginx :

/etc/init.d/nginx restart

Nous pouvons tester que Nginx répond bien sur le port 443 avec le certificat que nous avons créé, en lançant la commande :

curl -k https://nginx.poc.tls

L'option -k ou --insecure permet de passer en mode non sécurisé. Cela indique à Curl de ne pas vérifier le certificat. Cependant, nous souhaitons rester en mode sécurisé. Pour ce faire, nous devons installer l'autorité de certificat sur chaque conteneur, machine physique… qui devra avoir accès à notre conteneur Nginx.

Installation de l'autorité de certificat

Afin de ne plus avoir d'erreur de vérification du certificat, nous devons installer notre autorité de certificat dans notre système.

Commençons par créer un dossier nommé mon-ca-certificat dans le dossier /usr/local/share/ca-certificates. Le dossier ca-certificates permet de stocker les autorité de certificat. Une fois le fichier ca.crt copié dans le dossier que nous avons créé, nous allons pouvoir lancer la mise à jour de notre base de certificats :

cp ca.pem /usr/local/share/ca-certificates/mon-ca-certificat/ca.crt
/usr/sbin/update-ca-certificates

Le résultat de la dernière commande doit indiquer qu'un nouveau certificat à été ajouté :

Updating certificates in /etc/ssl/certs...
1 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d...
done.

Relancer la commande curl https://nginx.poc.tls

Le retour de cette commande est la suivante :

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>