Clé SSH : phrase de passe oubliée et ssh-agent

Une clé privée protégée fait réapparaître la même invite à chaque connexion, Enter passphrase for key '/home/alice/.ssh/id_ed25519':, tant qu’aucun programme ne garde la clé déchiffrée en mémoire. Un agent SSH, lancé par ssh-agent et alimenté par ssh-add, conserve cette clé pendant toute la vie de l’agent et supprime la ressaisie ; il ne restitue jamais la phrase de passe, et une phrase oubliée le reste. Le comportement décrit est celui d’OpenSSH 9.2p1 sous Debian 12 (bookworm), paquet openssh-client en version 1:9.2p1-2+deb12u7, et d’OpenSSH 9.6p1 sous Ubuntu 24.04 LTS, paquet 1:9.6p1-3ubuntu13 ; ces deux distributions Linux acceptent les mêmes commandes.
Sommaire
- Étape 1 : ssh-add -l montre ce que l’agent contient, ou son absence
- Étape 2 : ssh-agent -s exporte SSH_AUTH_SOCK et SSH_AGENT_PID dans le shell courant
- Étape 3 : ssh-add charge la clé et ne demande la phrase de passe qu’une fois
- Étape 4 : AddKeysToAgent remet la clé dans l’agent à la première connexion
- Le piège : ssh ne dit pas que la phrase de passe est fausse, il la redemande
- Phrase de passe oubliée : ssh-keygen -p n’essaie qu’une fois
- Error connecting to agent : la variable pointe vers un socket disparu
- Cinq questions concrètes
Étape 1 : ssh-add -l montre ce que l’agent contient, ou son absence
ssh-add -l
Trois réponses sont possibles et chacune oriente la suite. Une liste de lignes signifie qu’un agent répond et qu’il détient déjà des clés. La phrase The agent has no identities. signifie que l’agent tourne mais que rien n’y est chargé. Le message Could not open a connection to your authentication agent. signifie que la variable SSH_AUTH_SOCK n’est pas définie dans ce shell. ssh-add(1) documente les codes de retour correspondants : 0 pour une réussite, 1 pour une opération échouée, 2 pour un agent injoignable.
À l’écran, une clé chargée s’affiche dans cet ordre : taille en bits, empreinte SHA256, commentaire, type.
256 SHA256:uNiVztksCsDhcc0u9e8BujQXVUpKZIDTMczCvj3tD2s alice@portable (ED25519)
L’empreinte est celle de la clé publique, et ssh-keygen -lf ~/.ssh/id_ed25519.pub affiche la même valeur SHA256 par défaut. Sur Ubuntu avec GNOME, le trousseau de connexion fournit un agent dès l’ouverture de session : ssh-add -l répond sans que ssh-agent ait été lancé à la main.
Étape 2 : ssh-agent -s exporte SSH_AUTH_SOCK et SSH_AGENT_PID dans le shell courant
eval "$(ssh-agent -s)"
Sans agent, cette ligne démarre le processus et pose les deux variables qui permettront aux programmes lancés ensuite depuis ce shell de le joindre. Le eval est indispensable : ssh-agent -s se contente d’imprimer des commandes sur la sortie standard.
SSH_AUTH_SOCK=/tmp/ssh-XXXXXXkT9d2p/agent.4821; export SSH_AUTH_SOCK; SSH_AGENT_PID=4821; export SSH_AGENT_PID; echo Agent pid 4821;
Sur OpenSSH 9.2p1, le socket est créé dans un répertoire aléatoire sous $TMPDIR, par défaut /tmp, sur le modèle /tmp/ssh-XXXXXXXXXXXX, et le fichier s’appelle agent.<pid> ; c’est la valeur exacte que prend SSH_AUTH_SOCK. Deux variantes servent ensuite : ssh-agent -t 8h fixe une durée de vie maximale par défaut pour les clés ajoutées, et ssh-agent -k arrête l’agent désigné par SSH_AGENT_PID.
À l’écran, la vérification qui suit doit répondre que l’agent est joignable et vide.
ssh-add -l
The agent has no identities.
Les deux variables ne valent que pour le shell où le eval a été exécuté et pour ses processus enfants. Un autre terminal ne les voit pas, et y lancer ssh-agent de nouveau crée un second agent qui ignore les clés du premier. C’est pourquoi eval "$(ssh-agent -s)" n’a pas sa place dans ~/.bashrc : chaque terminal ouvrirait son propre agent, invisible pour les autres.
Étape 3 : ssh-add charge la clé et ne demande la phrase de passe qu’une fois
ssh-add ~/.ssh/id_ed25519
La commande lit la phrase de passe sur le terminal, déchiffre la clé et n’envoie que le matériel privé à l’agent, qui le garde en mémoire ; le fichier sur disque reste chiffré et rien de la phrase de passe n’y est écrit. Sans nom de fichier, ssh-add essaie les noms par défaut ~/.ssh/id_rsa, ~/.ssh/id_ecdsa, ~/.ssh/id_ecdsa_sk, ~/.ssh/id_ed25519 et ~/.ssh/id_ed25519_sk.
À l’écran, l’invite puis la confirmation, avec le commentaire de la clé entre parenthèses.
Enter passphrase for /home/alice/.ssh/id_ed25519: Identity added: /home/alice/.ssh/id_ed25519 (alice@portable)
Le contrôle qui compte vient juste après.
ssh-add -l
256 SHA256:uNiVztksCsDhcc0u9e8BujQXVUpKZIDTMczCvj3tD2s alice@portable (ED25519)
Une phrase erronée réaffiche Bad passphrase, try again for /home/alice/.ssh/id_ed25519: sans limite de tentatives, et une entrée vide abandonne le chargement. Un fichier de clé lisible par le groupe ou par les autres est refusé avec Permissions 0644 for '/home/alice/.ssh/id_ed25519' are too open. suivi de This private key will be ignored. ; la correction tient en chmod 600 ~/.ssh/id_ed25519, sujet détaillé dans permissions et utilisateurs. Une clé chargée sans option -t ne s’efface jamais tant que l’agent vit, ssh-agent(1) documentant une durée de vie maximale par défaut de « forever » quand ni ssh-agent -t ni ssh-add -t ne l’ont fixée.
ssh-add -t 8h ~/.ssh/id_ed25519
À l’écran, la ligne suivante confirme la limite.
Lifetime set to 28800 seconds
Le retrait se fait par ssh-add -d ~/.ssh/id_ed25519 pour cette clé, par ssh-add -D pour toutes, ou en laissant l’agent s’arrêter.
Étape 4 : AddKeysToAgent remet la clé dans l’agent à la première connexion
Les trois étapes précédentes valent pour la session courante. Pour ne pas recommencer à chaque redémarrage, la directive AddKeysToAgent fait ajouter la clé par ssh lui-même au moment où il la lit, comme le ferait ssh-add. Dans ~/.ssh/config :
Host *
AddKeysToAgent yes
IdentityFile ~/.ssh/id_ed25519
La valeur par défaut d’OpenSSH est no, et l’option existe depuis OpenSSH 7.2, publié le 29 février 2016. Elle accepte aussi ask, confirm et un intervalle de temps qui devient la durée de vie de la clé dans l’agent ; IdentityAgent choisit un socket précis, IdentityAgent none désactive tout agent pour un hôte donné.
À l’écran, la première connexion qui suit le démarrage de la session redemande la phrase de passe une fois, les suivantes non. Le contrôle se fait dans le même shell, juste après cette première connexion.
ssh-add -l
256 SHA256:uNiVztksCsDhcc0u9e8BujQXVUpKZIDTMczCvj3tD2s alice@portable (ED25519)
Deux conditions pour que l’effet se produise : un agent joignable, donc SSH_AUTH_SOCK défini dans le shell qui lance ssh, et une clé pas encore présente dans cet agent. Sur Ubuntu avec GNOME, l’agent du trousseau remplit la première condition sans intervention, et le wiki GNOME documente que les clés de ~/.ssh accompagnées d’un fichier .pub y sont chargées automatiquement. Le reste de la configuration cliente est décrit dans le guide SSH.
Le piège : ssh ne dit pas que la phrase de passe est fausse, il la redemande
Avec une phrase erronée, le client ssh n’affiche aucune erreur de déchiffrement : il réaffiche son invite et recommence, autant de fois que NumberOfPasswordPrompts, dont la valeur par défaut est 3. La trace n’existe qu’au niveau debug, sous la forme debug2: bad passphrase given, try again..., et la tentative se termine par :
alice@192.0.2.10: Permission denied (publickey).
Chercher une faute dans authorized_keys ou dans les droits du serveur part alors du mauvais côté : le client n’a jamais produit de signature. Seule une clé absente de l’agent évite l’invite, une clé chargée avec une mauvaise phrase la fait revenir.
Phrase de passe oubliée : ssh-keygen -p n’essaie qu’une fois
ssh-keygen -p -f ~/.ssh/id_ed25519
Après avoir constaté que le fichier ne se déchiffre pas avec une chaîne vide, ssh-keygen demande l’ancienne phrase de passe une seule fois et s’arrête au premier échec.
Enter old passphrase: Failed to load key /home/alice/.ssh/id_ed25519: incorrect passphrase supplied to decrypt private key
Le message vient du déchiffrement du fichier, pas d’un problème de droits, et aucune option de ssh-keygen ne contourne cette étape : le projet OpenSSH ne fournit aucune commande de récupération. Si la clé est encore chargée dans un agent vivant, elle continue de signer jusqu’à l’arrêt de l’agent, mais la phrase ne peut être ni lue ni remplacée ; une fois l’agent disparu, la clé privée est inutilisable. Le remède est une nouvelle paire, créée puis installée sur les serveurs.
ssh-keygen -t ed25519 ssh-copy-id -i ~/.ssh/id_ed25519.pub alice@192.0.2.10
À l’écran, la création affiche Generating public/private ed25519 key pair., puis Your identification has been saved in /home/alice/.ssh/id_ed25519 et Your public key has been saved in /home/alice/.ssh/id_ed25519.pub ; ssh-copy-id termine par Number of key(s) added: 1. Reste à supprimer l’ancienne ligne dans ~/.ssh/authorized_keys de chaque machine, sinon la clé perdue continue d’y être acceptée.
Error connecting to agent : la variable pointe vers un socket disparu
ssh-add -l
Error connecting to agent: No such file or directory
Ce message ne signale pas un agent absent, mais un chemin mort : SSH_AUTH_SOCK est défini et désigne un socket qui n’existe plus, typiquement après un redémarrage quand la variable a été figée dans un fichier de session ou restaurée par un multiplexeur de terminaux. Jusqu’à OpenSSH 10.0p1, le socket est créé sous /tmp, répertoire vidé au redémarrage ; les notes de version d’OpenSSH 10.1, datées du 6 octobre 2025, annoncent le déplacement des sockets d’agent de /tmp vers ~/.ssh/agent, afin que l’agent supprime lui-même ses sockets périmés. Debian 13 livre OpenSSH 10.0p1, paquet 1:10.0p1-7, et conserve donc l’ancien emplacement. Le remède consiste à repartir sur des variables cohérentes.
unset SSH_AUTH_SOCK eval "$(ssh-agent -s)" ssh-add ~/.ssh/id_ed25519
À l’écran, ssh-add -l répond The agent has no identities. juste après le second eval, puis liste la clé une fois le chargement terminé.
Cinq questions concrètes
Peut-on retrouver une phrase de passe oubliée avec un outil de récupération ?
Non. ssh-keygen -p exige l’ancienne phrase et n’essaie qu’une fois, puis s’arrête sur Failed to load key ...: incorrect passphrase supplied to decrypt private key, et OpenSSH n’embarque aucune fonction de récupération. Une clé encore chargée dans un agent vivant continue de servir, mais elle ne peut plus être rechargée ailleurs une fois l’agent arrêté : la sortie propre est une paire neuve installée par ssh-copy-id.
L’agent garde-t-il les clés après un redémarrage ?
Non : les clés vivent dans la mémoire du processus ssh-agent et disparaissent avec lui, à l’arrêt de l’agent comme au redémarrage. La directive AddKeysToAgent yes ne stocke pas la phrase de passe, elle la redemande une fois par nouvelle session d’agent. Sur un bureau Ubuntu, l’agent du trousseau de connexion conserve les clés d’une session à l’autre, ce qui explique qu’aucune invite ne réapparaisse après une reconnexion GNOME.
Combien de temps une clé reste-t-elle chargée dans l’agent ?
Indéfiniment par défaut : ssh-agent(1) documente une durée de vie maximale de « forever » quand aucune option n’est passée. ssh-add -t 8h ~/.ssh/id_ed25519 applique la limite à une clé et affiche Lifetime set to 28800 seconds, tandis que ssh-agent -t 8h fixe la limite par avance pour toutes les clés ajoutées ensuite ; à l’expiration, la clé est retirée et l’invite réapparaît.
Le transfert d’agent supprime-t-il la ressaisie sur un serveur distant ?
Oui, ssh -A et ForwardAgent yes font utiliser vos clés locales depuis la machine distante, sans y installer de clé. ssh_config(5) rappelle que la valeur par défaut est no et prévient qu’un utilisateur capable de contourner les permissions du socket sur la machine distante peut s’authentifier avec l’agent local ; pour une machine administrée durablement, une clé dédiée à ce serveur reste préférable.
Pourquoi ssh-add -l répond-il The agent has no identities. juste après un redémarrage ?
Parce que l’agent tourne encore mais a perdu son contenu, ou parce qu’un nouvel agent vide a remplacé l’ancien. Le contrôle se fait avec ssh-add -l puis echo $SSH_AUTH_SOCK : un socket sous /tmp/ssh-XXXXXXXXXXXX et une liste vide appellent un simple ssh-add ~/.ssh/id_ed25519, tandis qu’une variable pointant vers un répertoire disparu se traite avec unset SSH_AUTH_SOCK avant de relancer un agent.
Sources : ssh-agent(1), durée de vie par défaut des identités, option -t, socket et variable SSH_AUTH_SOCK, ssh-add(1), option -t, identités par défaut et codes de retour, ssh_config(5), AddKeysToAgent, IdentityAgent et ForwardAgent, notes de version OpenSSH 7.2 du 29 février 2016, option AddKeysToAgent, notes de version OpenSSH 10.1 du 6 octobre 2025, sockets d’agent déplacés de /tmp vers ~/.ssh/agent, code source ssh-add.c, ssh-keygen.c, authfile.c et sshconnect2.c de la version 9.2p1 pour les messages cités, wiki GNOME, agent SSH de gnome-keyring et clés de ~/.ssh accompagnées d’un .pub, changelog Debian bookworm, openssh 1:9.2p1-2+deb12u7. Versions relevées : openssh-client 1:9.2p1-2+deb12u7 sous Debian 12, 1:9.6p1-3ubuntu13 sous Ubuntu 24.04 LTS, 1:10.0p1-7 sous Debian 13.