Pourquoi des certificats plutôt que des clés

SSH fait confiance au premier contact. Connectez-vous à une nouvelle machine et il vous montre une empreinte en vous demandant si vous êtes sûr. Personne ne vérifie. Tout le monde tape yes. C’est la même habitude que de passer outre un avertissement du navigateur, et c’est exactement ce dont une machine placée au milieu a besoin que vous fassiez.

Dans l’autre sens, ce n’est pas mieux. Chaque serveur garde un fichier authorized_keys par utilisateur, et chacun grossit. Des clés sont ajoutées et jamais retirées. Quelqu’un s’en va, et sa clé reste sur une machine dont personne ne se souvient jusqu’au jour où ça compte. Reconstruisez un serveur et chaque client crie que la clé d’hôte a changé, alors les gens apprennent aussi à effacer l’avertissement.

Une autorité de certification SSH met fin aux deux. L’AC signe la clé de chaque hôte, et les clients font confiance à l’AC, pas à une liste d’empreintes. L’AC signe la clé de chaque utilisateur pour quelques heures, et les serveurs font confiance à l’AC, pas à une liste de clés. Rien à accepter à la première connexion, rien à nettoyer quand quelqu’un part, et un certificat utilisateur qui meurt de lui-même d’ici demain.

C’est une installation différente du côté X.509 de step-ca couvert dans Votre propre autorité de certification : step-ca dans un conteneur, et c’est pourquoi elle a son propre article. Même conteneur, autres clés, autres fichiers sur chaque machine. Tout ce qui suit a été lancé avec step-ca 0.30.2 et OpenSSH 10.0 dans un pod Podman.

Sans ACAvec step-ca
Un client rencontre un nouveau serveurAffiche une empreinte, vous tapez yesVérifie le certificat d’hôte contre l’AC, ne dit rien
Un serveur est reconstruitChaque client prévient que la clé a changéSignez la nouvelle clé, les clients ne remarquent rien
Un utilisateur obtient un accèsSa clé va dans authorized_keys sur chaque serveurL’AC signe sa clé, chaque serveur l’accepte
Un utilisateur s’en vaRetrouver et supprimer sa clé sur chaque serveurCesser de signer ; son certificat est mort en 16 heures
Ce que garde chaque serveurUn authorized_keys par utilisateurUne clé publique d’AC
Qui signe quoi, et qui fait confiance à quoistep-caclé d'AC d'hôteclé d'AC utilisateurClientcertificat utilisateur, 16 happrouve l'AC d'hôteServeurcertificat d'hôte, 30 joursapprouve l'AC utilisateursigne la clé utilisateursigne la clé d'hôtessh, sans questionchacun vérifie lecertificat de l'autre
L’AC signe les deux côtés. Le client n’a qu’à faire confiance à la clé de l’AC d’hôte, et le serveur qu’à la clé de l’AC utilisateur. Aucun ne tient de liste des clés de l’autre.

Activer l’AC SSH

Les clés SSH sont créées à la première mise en place de step-ca, ou jamais. Posez DOCKER_STEPCA_INIT_SSH=true au premier démarrage1, et le journal montre deux clés de plus :

SSH Host CA Key: ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAy...
SSH User CA Key: ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAy...
CléSigneQui lui fait confiance
AC d’hôteLa clé d’hôte de chaque serveurChaque client, dans known_hosts
AC utilisateurLa clé de connexion de chaque personneChaque serveur, dans sshd_config

Il ajoute aussi un provisioner sshpop, qui permet ensuite à un hôte de renouveler son propre certificat. Si l’AC tourne déjà sans SSH, il n’y a aucun interrupteur à basculer. C’est une nouvelle AC.

Signer l’hôte

Prenez la clé d’hôte existante du serveur, signez-la, et rendez le certificat au serveur :

step ssh certificate --host --sign \
  --provisioner admin --provisioner-password-file prov-pass \
  nas.home.example ssh_host_ecdsa_key.pub

L’ordre compte. Avec les options du provisioner après le nom d’hôte et le fichier de clé, step a refusé :

too many positional arguments were provided in 'step ssh certificate <key-id> <key-file>'

Mettez toutes les options en premier et il signe. Le certificat, tel que le lit ssh-keygen -L :

ChampValeur
Typeecdsa-sha2-nistp256-cert-v01@openssh.com host certificate
Key IDnas.home.example
Principalsnas.home.example
Validité30 jours, de 2026-10-09T18:34:30 à 2026-11-08T17:35:30

Le principal est le nom qu’un client doit utiliser pour se connecter. Connectez-vous par un nom qui ne figure pas sur le certificat et le client ne l’acceptera pas, donc signez tous les noms auxquels l’hôte répond.

Le serveur

Deux lignes dans sshd_config2 :

HostCertificate /etc/ssh/ssh_host_ecdsa_key-cert.pub
TrustedUserCAKeys /etc/ssh/ssh_user_ca_key.pub

HostCertificate remet le certificat d’hôte aux clients, et sa clé « must match a private host key already specified »2. TrustedUserCAKeys est la clé publique de l’AC utilisateur, « trusted to sign user certificates for authentication »2. Lancez sshd -t avant de redémarrer. Une faute de frappe dans l’un des deux chemins et sshd dit Could not load host certificate, ce qu’il vaut bien mieux découvrir maintenant que depuis une session bloquée.

Il n’y a aucun authorized_keys sur le serveur de test. ls /home/damien/.ssh/authorized_keys renvoie No such file or directory, et les connexions ci-dessous fonctionnent quand même.

L’utilisateur

L’AC crée la paire de clés et la signe d’un coup :

step ssh certificate damien id_ecdsa \
  --provisioner admin --provisioner-password-file prov-pass
ChampValeur
Typeuser certificate
Principalsdamien
Validité16 heures
Extensionspermit-agent-forwarding, permit-port-forwarding, permit-X11-forwarding, permit-pty, permit-user-rc

Seize heures, c’est tout l’intérêt. Ça couvre une journée de travail et ça meurt dans la nuit. Révoquer un utilisateur revient surtout à ne pas signer pour lui demain.

Le client

Une ligne dans known_hosts remplace toutes les empreintes qu’il collecterait autrement3 :

@cert-authority *.home.example ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAy...

Elle dit : tout hôte sous home.example dont le certificat est signé par cette clé est authentique. C’est le marqueur @cert-authority qui en fait une ligne d’AC plutôt que la clé d’un seul hôte.

Ce que le test a montré

Les quatre depuis un client qui ne détient rien d’autre que le certificat utilisateur et cette unique ligne de known_hosts, avec StrictHostKeyChecking=yes, pour que rien ne puisse être accepté à la volée :

TestRésultat
Clé signée avec son certificat, en tant que damienlogged in as damien, sortie 0
Même clé, certificat retiréPermission denied (publickey,password,keyboard-interactive)
Certificat utilisé pour se connecter en rootPermission denied : le certificat ne nomme que damien
Client sans la ligne de l’AC d’hôteHost key verification failed.

Le troisième est celui que les gens ratent. Un certificat n’ouvre pas tous les comptes de la machine, seulement les principals qui y sont écrits. Une clé dans le authorized_keys de quelqu’un ne sait pas faire ça.

Le renouvellement

Un hôte renouvelle son propre certificat avec la clé qu’il détient déjà. C’est le provisioner sshpop, qui « allows a client to renew, revoke, or rekey an SSH certificate using that certificate for authentication with the CA »4. Sans mot de passe5 :

step ssh renew --force ssh_host_ecdsa_key-cert.pub ssh_host_ecdsa_key
Numéro de sérieValide jusqu’au
Signé151663258693294169972026-11-08 17:35:30
Renouvelé66789577897973167682026-11-08 17:35:59

Un nouveau numéro de série et 30 jours neufs. Mettez-le sur une minuterie hebdomadaire et l’hôte n’expire jamais. Rechargez sshd ensuite, sinon l’ancien certificat reste en mémoire.

Les utilisateurs renouvellent en redemandant. Un step ssh certificate par jour, ou à la première connexion de la journée, et c’est tout le travail.

Là où ça coince

CasCe qui se passeQue faire
AC en panneLes certificats existants continuent de marcher ; personne n’en obtient de nouveauFaire tourner l’AC sur quelque chose qui reste debout ; les utilisateurs ont 16 heures de marge
Le certificat d’hôte expireLes clients refusent l’hôte, comme un inconnuUne minuterie de renouvellement, et sshd rechargé après
Un utilisateur doit partir aujourd’hui, pas demainSon certificat marche jusqu’à son expirationRevokedKeys dans sshd_config accepte une liste de clés révoquées2
Nom d’hôte absent des principalsLe client refuse l’hôteSigner tous les noms auxquels il répond
AC SSH non créée à l’installationAucun moyen de l’ajouterUne nouvelle AC, montée avec SSH activé
Les clés SSH de l’AC voléesQui les détient peut se connecter partout et se faire passer pour n’importe quel hôteGarder l’AC sur sa propre machine, sauvegardée, hors ligne si possible

Le dernier est le prix à payer. Chaque fichier authorized_keys était son propre petit risque. Il y en a maintenant un gros, à un seul endroit. C’est mieux, parce qu’un seul endroit peut être surveillé et verrouillé, mais seulement si quelqu’un le fait.

La confiance là où on peut la vérifier

L’invite d’empreinte et le fichier authorized_keys ont un point commun. Les deux demandent à une personne de prendre une décision de confiance sans aucune information, chaque jour, pour toujours. Les gens ne sont pas bons à ça et ne le seront jamais, alors ils cessent de décider et se mettent à taper yes.

Une AC déplace cette décision à un seul endroit, une seule fois, là où elle peut être prise correctement. C’est toute l’idée, et c’est la même que derrière chaque norme qui vaut la peine : faire la chose soigneusement une fois, l’écrire, et cesser de demander aux gens de la faire de tête cent fois par semaine. La machine vérifie la signature. Vous vérifiez l’AC. C’est une division du travail qui tient.


  1. smallstep/certificates — docker/entrypoint.sh — DOCKER_STEPCA_INIT_SSH=true ajoute --ssh à step ca init. ↩︎

  2. OpenBSD manual — sshd_config(5) — HostCertificate : « The certificate’s public key must match a private host key already specified by HostKey » ; TrustedUserCAKeys : « public keys of certificate authorities that are trusted to sign user certificates for authentication » ; RevokedKeys : « Keys listed in this file will be refused for public key authentication ». ↩︎ ↩︎ ↩︎ ↩︎

  3. OpenBSD manual — sshd(8), SSH_KNOWN_HOSTS FILE FORMAT — le marqueur « @cert-authority » « to indicate that the line contains a certification authority (CA) key ». ↩︎

  4. Smallstep — Provisioners, SSHPOP — « An SSHPOP provisioner allows a client to renew, revoke, or rekey an SSH certificate using that certificate for authentication with the CA. » ↩︎

  5. Smallstep — step ssh renew — la commande utilisée pour renouveler le certificat d’hôte. ↩︎