Certificats x509 pour SSH
Niveau :
Résumé : SSH et certificats x509
Vous avez une ferme de serveurs ? Vous avez une ferme d’utilisateurs ? Vous avez déjà une infrastructure de gestion de clés pour des certificats x509 (ssl) ?
Si vous répondez oui à deux de ces points alors cet article va vous intéresser.
Sachez qu’il est possible d’utiliser des certificats x509 avec ssh. Quel intérêt ? Tout simplement vous pouvez réutiliser votre PKI si vous en avez déjà une en x509. Ensuite les certificats fonctionnent par un système de signature hiérarchisée, donc il n’est plus nécessaire de mettre en place un système de distribution des clés des utilisateurs sur les machines. Et inversement, les utilisateurs n’auront plus à se reposer sur leur pifomètre pour accepter les clés des serveurs à leur première connexion.
Maintenant qu’on sait qu’on va pouvoir vendre de la sécurité à notre boss tout en évitant de se farcir des systèmes de synchronisation, on va pouvoir se lancer dans les choses sérieuses.
Compilation
Tout d’abord il nous faut une version de ssh qui supporte ce mode de fonctionnement. On la trouvez chez un certain Roumen Petrov. Bon, petite déception, il ne fournit que des patchs. A nous d’en faire un vrai ssh compilé. Pour une fois, ça va être une peu plus difficile pour les debianistes. Pour ceux qui recompilent leur ssh directement :
# à adapter à vos besoins et à votre version $ wget http://www.roumenpetrov.info/openssh/x509-6.1.1/openssh-5.1p1+x509-6.1.1.diff.gz $ cd openssh-source $ zcat ../openssh-5.1p1+x509-6.1.1.diff.gz | patch -p1 $ ./configure $ make $ make install
Pour ceux qui sont sur debian, il serait quand même plus sympa de se refaire un paquet. Le problème est que le patch de Roumen Petrov s’applique mal sur des sources debian. Il y a donc 3 rejets à appliquer avant de pouvoir lancer la compilation :
# récupération des sources debian $ apt-get source openssh # récupération du patch $ wget http://www.roumenpetrov.info/openssh/x509-6.1.1/openssh-5.1p1+x509-6.1.1.diff.gz $ cd openssh-5.1p1 $ zcat ../openssh-5.1p1+x509-6.1.1.diff.gz | patch -p1 # ICI relisez les fichiers .rej et appliquez à la main, c'est assez simple # recompilation $ dpkg-buildpackage -rfakeroot -b # installation $ cd .. $ su $ dpkg -i openssh-client*.deb openssh-server*.deb
Pour ceux qui sont toujours en etch vous pouvez soit upgrader ssh en récupérant le paquet source de lenny soit utiliser la version etch avec une version plus ancienne du patch.
Pour la méthode upgrade avec etch, modifiez le fichier debian/control qui se trouve dans le répertoire source ssh et supprimez les versions de libssl et lsb-base indiquées dans les dépendances avant de compiler. Cela marche très bien.
Pour ceux qui voudraient rester en ssh4.1, appliquez le patch de Roumen Petrov et forcez l’application du patch avec les erreurs. Ensuite listez les fichier .rej (ils sont tous à la racine) et appliquez les à la main (retrouver la bonne ligne, ajouter …). C’est un peu plus long.
Utilisation
Ça y est le nouveau ssh est installé sur le serveur et sur le client. Maintenant utilisons un certificat pour se connecter au serveur et prouver que ça marche.
Tout d’abord il nous faut une autorité de certification, c’est à dire un certificat qui a le droit de signer d’autres certificats et que nous installerons partout (l’article explique comment la créer et l’utiliser). Avec cette autorité, il faut générer deux paires de clés : une paire pour le serveur, une paire pour le client. Rien n’oblige à avoir la même autorité pour les deux, mais cela simplifie les exemples, c’est donc ce que je vais faire.
On a donc :
- ca.crt : le certificat de l’autorité
- server.crt et server.key : le certificat et la clé à utiliser sur le serveur ssh
- client.crt et client.key : le certificat et la clé à utiliser sur le client ssh
Authentification du serveur
Commençons par configurer l’authentification du serveur par le client. Le client sera sûr que le serveur est reconnue par une autorité.
Côté serveur
Installons le certificat sur le serveur ssh. On place la clé dans un nouveau fichier pour le serveur :
$ cat server.key server.crt > /etc/ssh/ssh_host_x509_key $ chmod 600 /etc/ssh/ssh_host_x509_key # mise à jour de la clé publique pour la forme $ ssh-keygen -y -f /etc/ssh/ssh_host_x509_key > /etc/ssh/ssh_host_x509_key.pub
Et on ajoute cette clé à celle que le serveur envoie au client pour authentification en ajoutant une ligne/etc/ssh/sshd_config :
HostKey /etc/ssh/ssh_host_x509_key
Vous pouvez même commenter les anciennes lignes HostKey si vous voulez forcer l’utilisation de x509, mais je ne pense pas que ce soit judicieux (par contre ça permet d’être sur de ce qu’on teste). Et hop on relance le serveur.
# n'ayez pas peur cela ne coupe pas les connexions existantes $ /etc/init.d/ssh restart
Côté client
Maintenant il faut que le client accepte cette clé. On va lui dire qu’il peut accepter tout ce qui a été signé par notre autorité. Pour cela, il suffit de copier le certificat de l’autorité dans /etc/ssh/ca/ca-bundle.crt (vous pouvez mettre toutes les autorités que vous voulez dans ce fichier) :
$ cp ca.crt /etc/ssh/ca/ca-bundle.crt
Attention : ssh vérifie que le certificat est bien signé par une autorité valide mais cela ne veut pas dire qu’il accepte directement la clé. Il passe toujours par une vérification utilisateur comme expliqué dans un autre article. Attention : ssh refuse les clés mal signées mais autorise les clés sans certificat. A l’utilisateur d’accepter ou refuser la clé. Attention : ssh vérifie la chaine de certification, mais ne vérifie pas que le cn correspond au nom du serveur.
A noter qu’il est dommage que la vérification de la chaine de certification se fasse après l’acceptation par le client.
Authentification du client
Cette fois c’est le serveur qui va vérifier que le client dispose d’un certificat vérifié par une autorité.
Côté client
Pour utiliser notre certificat comme identité, on le copie sur le client :
$ cat client.key client.crt > ~/.ssh/id_x509 $ chmod 600 ~/.ssh/id_x509 # on met a jour la clé publique $ ssh-keygen -y -f ~/.ssh/id_x509 > ~/.ssh/id_x509.pub
Et on configure le client pour qu’il l’utilise (au choix dans /etc/ssh/ssh_config ou dans ~/.ssh/config) :
Host * IdentityFile ~/.ssh/id_x509
Côté serveur
Maintenant il faut que le serveur accepte cette clé. On va lui dire qu’il peut accepter tout ce qui a été signé par notre autorité. Pour cela, il suffit de copier le certificat de l’autorité dans /etc/ssh/ca/ca-bundle.crt (vous pouvez mettre toutes les autorités que vous voulez dans ce fichier) :
$ cp ca.crt /etc/ssh/ca/ca-bundle.crt
Et on adapte l’authorized_keys sur le serveur. Pour cela deux solutions, la première est de copier tel quel le fichier id_x509.pub généré précédemment. Ça marche, mais ce n’est pas très intéressant. Puisqu’on a des certificats qui sont vérifiés autant en profiter et ne donner que le DN ce qui nous permettra de le changer.
# on réutilise le certificat pour sortir le dn au bon format $ openssl x509 -noout -subject -in client.crt -nameopt RFC2253 >> ~/.ssh/authorized_keys
Attention : ssh refuse les clés mal signées mais autorise les clés sans certificat. A l’utilisateur de remplir son authorized_keys correctement
Conclusion
Cet article commence à être long, je vais donc m’arrêter ici. Vous voyez qu’il est possible de mettre en place des certificats pour ssh sans trop se forcer. Le patch de Roumen Petrov est bien fait puisqu’il ajoute beaucoup d’options (je les ai laissé ici à leur valeur par défaut pour simplifier l’article) et surtout, elles sont toutes documentées dans les pages de manuel. De plus le support de x509 est étendu à tous les outils ssh, c’est à dire le client, le serveur, mais aussi ssh-keygen et ssh-agent. En dehors du man, la meilleure documentation c’est le README.
Tout cela est bien pratique mais seul un usage basique a été couvert ici. Un des gros avantages de l’utilisation des certificats est de pouvoir gérer des listes de révocation pour interdire automatiquement des certificat qui ne sont plus valides (l’utilisateur est parti, la clé est trop vieille …). Nous en parlerons surement dans un prochain article.