Table des matières
Nginx et ssl_client_certificate
Mise en place d'une mini infrastructure NGINX avec SSL , avec des clés SSL signés pour les clients.
Il s'agit pas seulement de chiffrer la communication, mais aussi de refuser les clients qui n'utilisent pas une clé reconnue ou revokée par “notre” autorité.
~~READMORE~~
préparation
# cd /etc/nginx/ # mkdir ssl # chmod 0700 ssl # cd ssl # mkdir mon_site
Serveur
Générer la clé privée avec une pass-phrase…
# openssl genrsa -des3 -out server.key 2048
Virer la pass-phrase:
# cp server.key server.key.bak # openssl rsa -in server.key.bak -out server.key
Générer un certificat:
# openssl req -new -sha256 -key server.key -out server.csr
Auto-signé le certificat:
# openssl x509 -req -days 3650 -sha256 -in server.csr -signkey server.key -out server.crt
Au final, on a ça d'interessant:
server.key
server.csr
server.crt
CA
Génération de la clé privée:
# openssl genrsa -out ca.key 2048
Génération de la clé publique de l'autorité:
# openssl req -new -sha256 -x509 -nodes -days 3650 -key ca.key -out ca.crt
Remplir les champs, particulièrement le “common name”.
Créer le fichier qui va attribuer un numéro unique pour chaque certificat:
# echo "00" > ca.srl
Pour cette étape, on a généré les fichiers:
ca.key
ca.crt
ca.srl
Clients
Création des clés d'un client:
# openssl req -newkey rsa:2048 -sha256 -nodes -keyout client1.key -out client1.csr
Signer les clés:
# openssl x509 -req -in client1.csr -days 3650 -CA ca.crt -CAkey ca.key -out client1.crt
client1.key
client1.csr
client1.crt
Pour les “serial”, on aurait pu utiliser “-set_serial
” ou “-CAcreateserial
”, mais on a préféré préparer un fichier “ca.srl
” …
Clients : batch
Lors de la création des clés, on peut outre passer la phase de saisie en ajoutant l'option “-subj
” suivit des informations qu'on aurait du saisir:
Donc, il suffit d'ajouter l'option “-batch
” suivit de (par exemple):
-subj "/C=FR/ST=France/L=Paris/O=Eez.fr/OU=www/CN=client1/emailAddress=nospam-ca@eez.fr"
P12
Conversion en “.p12” avec un mot de passe:
# openssl pkcs12 -export -clcerts -in client1.crt -inkey client1.key -out client1.p12 -passout pass:<PASSWORD>
Remplacer “<PASSWORD>
” par le mot de passe de votre choix.
Revokation
Créer le fichier de revokation
Source:
# cd /etc/nginx/ssl/mon_site
Faire une copie de la conf par défaut:
# cp /etc/ssl/openssl.cnf local-openssl.cnf
A apporter les modifications suivantes:
[ ca ] #default_ca = CA_default # The default ca section default_ca = myca [ myca ] # copy complète de la section "CA_default" # avec pour changement: dir = . ... crl_extensions = crl_ext ...
En clair:
- le répertoire de travail est le répertoire courant.
- on passe en crl V2 (source )
Si on a rien changé d'autres dans la conf par défaut, on peut préparer quelques fichiers comme cela:
# echo 00 > crlnumber # touch index.txt # mkdir crl
Générer le fichier des révokations, vide pour l'instant:
# openssl ca -config ./local-openssl.cnf -keyfile ca.key -cert ca.crt -gencrl -out crl/crl.pem
Revoker des clés
Il s'agit de révoker la signature des clés: les clés pourront être re-signés. |
# openssl ca -config ./local-openssl.cnf -keyfile ca.key -cert ca.crt -revoke client-client6.crt
Using configuration from ./local-openssl.cnf Adding Entry with serial number 09 to DB for /C=FR/ST=France/L=Paris/O=Eez.fr/OU=www/CN=client6/emailAddress=ca@eez.fr Revoking Certificate 09. Data Base Updated
Après chaque serie de révokation, le fichier “index.txt” est modifié.
Mettre a jour la base de revokation (à partir du fichier “index.txt” sans doute):
# openssl ca -config ./local-openssl.cnf -gencrl -keyfile ca.key -cert ca.crt -out crl/crl.pem -crldays 7
Il faudra aussi relancer “nginx
” pour qu'il prenne en charge le nouveau fichier de révokation.
-crldays X permet de dire combien de temps ce fichier est valide !!! Passé cette date limite, “nginx ” refuse tous les clients ! |
Donc: soit mettre un “crldays
” très lointain, soit ré-générer le fichier régulièrement, avant l'expiration.
Dans tout les cas, il faudra faire: /etc/init.d/nginx reload
.
Le fichier “crl ” a vocation a être publique… d'où la date de péremption avec “crldays ”. |
Tips
Examiner le contenu du fichier des revokations:
# openssl crl -in crl/crl.pem -noout -text
Vérifier si une signature est révoqué ou pas:
# openssl verify -CRLfile crl/crl.pem -CAfile ca.crt -crl_check client1.crt
Quand c'est révoké, on a:
... error 23 at 0 depth lookup:certificate revoked
Sinon, pour non révoké, on a:
... : OK
Configurer Nginx avec SSL
SSL dans Nginx
, pour faire court:
listen 0.0.0.0:443 ssl; #ssl on; # Les clés du serveur: ssl_certificate /etc/nginx/ssl/mon_site/server.crt; ssl_certificate_key /etc/nginx/ssl/mon_site/server.key; # Le certificat de l'autorité qui vérifie les clients ssl_client_certificate /etc/nginx/ssl/mon_site/ca.crt; ssl_verify_client on; # revokation: ssl_crl /etc/nginx/ssl/mon_site/crl/crl.pem;
Tips
ssl optional
Il y a des fois, on ne veut pas vérifier la clé de certains clients, parce qu'on estime qu'ils sont dans un réseau (local) de confiance…
Dans ce cas, on peut mettre en place des conditions du style:
- Si dans tel ou tel reseau: → ne pas vérifier le certificat et accepter le client.
- Sinon → suivre la procédure normale en validant le certificat du client.
Pour cela, voici les modifications a apporter dans la conf Nginx
:
ssl_verify_client optional; # Au lieu de "on"
Dans la ou les sections “location …
” , ajouter:
location / { # Une IP amie ? if ( $remote_addr != 212.212.212.212 ) { # Non set $test "1"; } # Le ssl est verifié ? if ( $ssl_client_verify != 'SUCCESS' ) { # Non set $test "${test}2"; } # Pas Amie et SSL non verifié ? if ( $test = '12' ) { # Oui: rejeter return 403; } # continuer la conf normale... proxy_pass http://127.0.0.1:8080/; access_log off; }
sub_filter
Pour que la réécriture du contenu des pages HTML fonctionne avec “sub_filter
”, il faut désactiver la compression “gzip” .
Le plus simple étant de vider l'entête “encoding” comme ceci:
proxy_set_header Accept-Encoding "";
A nous maintenant les:
sub_filter <h3>Hi</h3> '<h3>Hello World!</h3>'
examiner les certificats en ligne
$ echo | openssl s_client -connect mon_site:443
Enjoy !