Salut à tous, aujourd’hui on m’a demandé de regarder comment faire de l’authentification par certificat x509 sur un serveur Nginx. Je parle bien ici du client, pas du certificat serveur que vous obtenez avec let’s encrypt par exemple. Donc pour accéder au site web l’utilisateur devra présenter un certificat valide de l’AC que vous aurez défini.
Un certifi-quoi ?
Dans les faits, vous utilisez déjà des certificats x509 (délivrés par let’s encrypt, par exemple) pour authentifier votre site auprès de vos utilisateurs (et comme base pour chiffrer la connexion en HTTPS aussi). Ici ce qu’on souhaite faire c’est l’inverse, c’est à dire que le serveur va demander aux utilisateurs de s’authentifier, en présentant un certificat, avant de les laisser accéder au site.
Alors je suis désolé pour ceux qui ne captent rien aux certificats, ce n’est pas l’objet de cet article. Je pars du postula que si vous cherchez à authentifier vos clients par certificats, c’est que vous savez déjà ce que c’est… Sinon, je vous renvoi quand même (je suis sympa) vers ces sources (ici, là, là, et là) qui ne sont pas trop mauvaises. Mais ne rêvez pas trop, un bon cours sur les PKI ce n’est pas si évident que ça à trouver, et ça nécessite un peu de pratique, avec XCA par exemple.
Authentification par certificat client sur nginx
De quoi on a besoin ?
Dans nos prérequis :
On aura besoin :
- d’un serveur web avec un site de préférence en HTTPS ;
- d’une autorité de certification (AC) ;
- de certificats délivrés à nos utilisateurs par cet AC ;
- de la liste des certificats qui auront le droits d’accéder à notre site (parmi tout ceux délivrés par l’AC)
Activer l’authentification par certificat
Alors c’est assez facile avec nginx d’activer le contrôle du certificat client par rapport une AC, il suffit de rajouter les lignes suivante dans votre bloc « server » du fichier de config de votre site (probablement dans /etc/nginx/conf.d/ ou /etc/nginx/sites-available/) :
ssl_client_certificate /path/to/a/CA-cert.pem; ssl_verify_client on; # doc ssl_verify_depth 2; # n° à ajuster en fonction de votre chaine de certification
Et c’est tout, dans cette configuration, seul les clients détenant un certificat (et sa clé privé surtout) émis par l’AC, indiquée dans le fichier CA-cert.pem, pourront accéder à votre site.
Limiter l’accès par certificat à certains utilisateurs
La configuration au dessus, exige la présentation d’un certificat par le client, néanmoins, ne permet pas de gérer des groupes d’accès : tout utilisateur détenant un certificat émis par notre AC pourra rentrer.
Ce qu’on aimerai c’est pouvoir limiter l’accès à certaines sections d’un site à certains utilisateurs. La ça devient un tout petit peu plus tricky, mais ça se fait aussi. D’abord on doit définir notre liste d’utilisateur, pour cela on peut utiliser le module map.
map $ssl_client_s_dn $ssl_access { default 0; "~CN=Paul BISMUTH Entreprise" 1; "~CN=Jean Dupondt Stagiaire" 1; # etc. }
Ce bloc va affecter à la variable $ssl_access la valeur 1 ou 0, selon que la valeur de $ssl_client_s_dn « matche » ou non un des éléments de la liste.
On peut donc ensuite se servir de cette variable pour limiter l’accès à certains bloc « location » de notre site. Par exemple, ci dessous pour les url sous « /admin » :
location /admin { if ( $ssl_access = 0 ) { return 403; # => forbidden } }
Gérer des accès par zones
Dans la solution au dessus, on a un mode on/off. Mais dans le cas ou l’on souhaite gérer des accès sur plusieurs zones, cette solution est limité. Une bonne option trouvée sur StackOverFlow de gérer des accès par zone par certificat :
map $ssl_client_s_dn $ssl_access { default ""; "~CN=Paul BISMUTH Entreprise" -a-b-c-; "~CN=Jean Dupondt Stagiaire" -b-e-; # etc. } server { [...] location /admin/ { if ($ssl_access !~ -a-) { return 403; } } [...] location /interns { if ($ssl_access !~ -b-) { return 403; } } [...] }
Dans l’exemple, la zone « a » du site est accessible par les admins, la zone b par les stagiaires et les admins.
Conclusion
Et voilà pour l’authentification par certificat client sur nginx : c’est pas bien compliqué, et vous pouvez faire des trucs plutôt marrant avec. Par exemple vous déployez vos certificats sur des tokens physiques. C’est bien sécu… mais seulement si vous gérez correctement vos certificats ! Donc il vous faut une bonne PKI pour ça.
Pour finir, clairement là je présente un usage d’entreprise plus que de particulier. Pour les particuliers, je vous conseille de gratter du côté des YubiKey pour faire une protection équivalente pour ssh par exemple.
Bonjour,
La même chose est-elle envisageable avec un certificat OpenPGP ?
Bonjour, pas à ma connaissance, et je ne connais pas de module pour Nginx qui ajoute ça au niveau du serveur web.
Par contre, ça à l’air de bien se faire au niveau applicatif web (i.e PHP ou équivalent) en signant un bout de texte (par exemple) avec ta clé.