Ce que cela résout
Avec des clés simples, chaque serveur garde une liste de clés autorisées, et chaque portable garde une liste de clés d'hôte. Avec 50 serveurs, ajouter ou retirer une personne oblige à modifier 50 fichiers, et les anciennes clés ont tendance à rester pour toujours.
Avec des certificats, les serveurs font confiance à une seule clé de CA. Vous signez la clé publique d'une personne pour une durée donnée, et quand le certificat expire, l'accès prend fin. Ce sont des certificats OpenSSH, pas ceux de type X.509 utilisés pour les sites web, et vous n'avez besoin d'aucune entreprise ni d'aucun service extérieur.
Créer la CA
ssh-keygen -t ed25519 -f user_ca -C "user-ca"
C'est une paire de clés ordinaire. Quiconque détient la moitié privée user_ca peut se connecter sous n'importe quel nom sur tous les serveurs qui lui font confiance : donnez-lui une phrase secrète solide et gardez-la hors de votre machine quotidienne et hors des serveurs. Utilisez une CA distincte pour les hôtes, comme indiqué plus bas.
Signer la clé publique d'un utilisateur
La personne vous envoie id_ed25519.pub, jamais la clé privée :
ssh-keygen -s user_ca -I "alice@example.com" -n deploy,alice -V +8h id_ed25519.pub
| Option | Signification |
|---|---|
-s user_ca | La clé privée de la CA utilisée pour signer. |
-I | L'identifiant de la clé. Il est écrit dans le journal du serveur à chaque connexion : faites-lui porter le nom de la personne. |
-n | Les principals : les noms pour lesquels ce certificat est valide. |
-V | La validité. +8h, +1d, ou une plage comme -5m:+1d, qui couvre aussi un serveur dont l'horloge retarde un peu. |
Le résultat est id_ed25519-cert.pub. Renvoyez-le à la personne, qui le place à côté de la clé privée. ssh le trouve alors par son nom, sans configuration supplémentaire. Rangé ailleurs, il lui faut une ligne CertificateFile dans ~/.ssh/config. Pour en lire un :
ssh-keygen -L -f id_ed25519-cert.pub
Sans -V, un certificat n'expire jamais, ce qui supprime une grande partie de l'intérêt.
Faire confiance à la CA côté serveur
Copiez user_ca.pub, uniquement la partie publique, vers /etc/ssh/user_ca.pub sur le serveur. Ajoutez ceci à la configuration de sshd, puis lancez sudo sshd -t et rechargez :
TrustedUserCAKeys /etc/ssh/user_ca.pub
L'utilisateur peut maintenant se connecter sans aucune ligne dans authorized_keys. Le journal du serveur indique qui c'était :
Accepted publickey for deploy from 203.0.113.50 port 56276 ssh2: ED25519-CERT SHA256:... ID alice@example.com (serial 0) CA ED25519 SHA256:...
Principals
Par défaut, le serveur exige que le nom du compte figure parmi les principals du certificat. Un certificat pour alice n'ouvre pas le compte deploy.
Pour utiliser des rôles plutôt que des noms de comptes, listez les principals acceptés pour chaque compte :
AuthorizedPrincipalsFile /etc/ssh/auth_principals/%u
Le fichier /etc/ssh/auth_principals/deploy contient alors un nom par ligne, par exemple ops, et vous signez avec -n ops. Avec ce réglage, le nom du compte n'est plus accepté automatiquement : seuls comptent les noms du fichier, et un compte sans fichier refuse les certificats.
Limiter ce qu'un certificat peut faire
Les options se fixent au moment de la signature. Ici, le certificat ne fonctionne que depuis un seul réseau et ne peut pas ouvrir de terminal :
ssh-keygen -s user_ca -I alice -n ops -V +1h -O source-address=203.0.113.0/24 -O no-pty id_ed25519.pub
-O clear supprime toutes les permissions par défaut, et vous pouvez ensuite remettre celles que vous voulez, par exemple -O clear -O permit-pty.
Quand une connexion échoue
Le client dit seulement Permission denied (publickey). La raison est dans le journal du serveur :
| Ligne de journal | Cause |
|---|---|
Certificate invalid: name is not a listed principal | Le compte ne figure pas dans la liste -n du certificat. |
Certificate invalid: expired | La date de fin est dépassée. Signez-le de nouveau. |
Refused by certificate options | Une limite comme source-address ne correspond pas. |
Authentication key ... revoked by file ... | La clé figure sur la liste de révocation. |
Révoquer un certificat avant son expiration
Gardez les certificats courts, pour en avoir rarement besoin. Pour le cas urgent, créez une liste de révocation de clés à partir de la clé publique et copiez-la sur chaque serveur :
ssh-keygen -k -f revoked.krl id_ed25519.pub
ssh-keygen -Q -f revoked.krl id_ed25519.pub
RevokedKeys /etc/ssh/revoked.krl
Ajoutez les clés suivantes à la même liste avec -u. Soyez prudent avec ce fichier : si sshd ne peut pas le lire, la connexion par clé publique est refusée pour tous les utilisateurs.
Pour les clés sans certificat, voir comment révoquer une clé SSH au départ de quelqu'un.
Certificats d'hôte
Les certificats d'hôte règlent l'autre sens. Vos utilisateurs ne voient plus l'invite d'hôte inconnu, car ils font confiance à une CA et non à chaque clé d'hôte. Signez la clé d'hôte publique du serveur avec -h, et listez les noms qu'on utilise pour s'y connecter :
ssh-keygen -t ed25519 -f host_ca -C "host-ca"
ssh-keygen -s host_ca -I server1 -h -n server1.example.com -V +52w ssh_host_ed25519_key.pub
Sur le serveur, avec ssh_host_ed25519_key-cert.pub dans /etc/ssh/ :
HostKey /etc/ssh/ssh_host_ed25519_key
HostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub
Sur chaque client, ajoutez une ligne à ~/.ssh/known_hosts, avec le contenu de host_ca.pub :
@cert-authority *.example.com ssh-ed25519 AAAA...
Le motif doit correspondre au nom avec lequel vous vous connectez. Sinon, ssh ignore la ligne et traite l'hôte comme inconnu, ou le refuse si StrictHostKeyChecking vaut yes. Les certificats d'hôte expirent aussi : renouvelez-les avant cette date. Voir known_hosts expliqué pour le fonctionnement du reste de ce fichier.
Quand les certificats valent la peine
Pour quelques serveurs et quelques personnes, des clés simples sont plus faciles. Les certificats commencent à être rentables quand des personnes arrivent et partent souvent, ou quand vous voulez un accès de courte durée avec un nom dans le journal. La partie difficile est le processus autour de la CA : qui peut signer, où vit la clé privée, et comment une personne obtient un nouveau certificat chaque jour. ssh-keygen vous donne la signature, pas ce processus.
Questions
Quelle différence entre une clé SSH et un certificat SSH ?
Un certificat est une clé publique signée par une CA, avec une liste de noms d'utilisateur autorisés et une date d'expiration. Un serveur qui fait confiance à la CA l'accepte sans ligne dans authorized_keys pour cette clé.
Comment savoir quand un certificat SSH expire ?
Lancez ssh-keygen -L -f id_ed25519-cert.pub. La ligne Valid indique le début et la fin de la validité.
Les certificats SSH remplacent-ils authorized_keys ?
Pour les connexions par certificat, oui : le serveur n'a besoin que de TrustedUserCAKeys. Les clés simples listées dans authorized_keys continuent de fonctionner à côté.
Sources
- ssh-keygen(1), section CERTIFICATES, manuel OpenBSD
- sshd_config(5), manuel OpenBSD
- sshd(8), SSH_KNOWN_HOSTS FILE FORMAT, manuel OpenBSD