Le jour où une clé SSH a fait chuter notre LCP pendant 6 heures
Jeudi, 16h. Un correctif urgent attendait : une régression sur le chargement des images produit faisait passer le LCP de 2.1s à 5.8s sur la landing principale. Le fix était prêt, testé en local, validé. Il suffisait de pousser en production.
Sauf que git push a renvoyé une erreur d’authentification. Le déploiement automatisé ne passait plus. Motif : la clé SSH privée du runner CI/CD ne correspondait plus à la clé publique présente sur le serveur de production. Quelqu’un avait régénéré la paire sur le bastion sans répercuter le changement dans les secrets du pipeline.
Résultat : le correctif est resté en attente 6 heures. Six heures où le LCP est resté dégradé, où la Search Console a continué d’enregistrer des scores « Mauvais » sur l’URL la plus critique du domaine.
On parle beaucoup de fetchpriority, de lazy-loading conditionnel, de préchargement des polices. Mais la capacité à corriger une régression en moins de 10 minutes dépend d’un mécanisme que personne n’audite : l’authentification SSH. Si ta clé publique n’est pas là où elle doit être, aucun npm run build ne sauvera ton LCP.
Pourquoi ta paire de clés SSH est un maillon direct de ta stratégie Core Web Vitals
Le SSH ne figure dans aucun article sur l’optimisation des Core Web Vitals. C’est normal : ce n’est pas un signal de classement, Googlebot ne fait pas de handshake SSH, le protocole est invisible pour le navigateur.
Pourtant, la chaîne qui relie un commit à un déploiement en production passe presque systématiquement par une authentification par clé publique. Si cette chaîne casse, un correctif de CLS à 0.12 reste bloqué dans le runner. Un script de purge de cache CDN ne s’exécute plus. Un rollback de version prend 40 minutes au lieu de 4.
On a mesuré sur notre infra : le temps médian entre le tag de release et le déploiement effectif est passé de 3 minutes à 47 minutes le jour où la clé du runner a expiré. Ce n’était pas un problème réseau, pas un goulot d’étranglement CPU. C’était une ligne dans authorized_keys qui pointait vers une clé révoquée.
Pense ta clé publique comme le premier filtre de ton MTTR. Si l’objectif est un MTTR sous les 5 minutes, traite tes clés SSH avec la même rigueur que tes variables d’environnement ou tes règles de pare-feu. Tu ne laisserais pas un token API expirer sans plan de rotation. Pourquoi tolères-tu une clé SSH sans commentaire ni date de création ?
Ed25519, RSA 4096, ECDSA : le choix du type de clé qui accélère ou freine tes connexions
La majorité des développeurs génèrent leur première paire avec ssh-keygen -t rsa et n’y reviennent jamais. C’est un héritage, pas une décision technique.
RSA demande des clés longues pour maintenir un niveau de sécurité acceptable. Une clé RSA 4096 bits impose une charge CPU non triviale lors du handshake SSH. Sur une connexion isolée, la différence est imperceptible. Dans un pipeline CI/CD qui ouvre 15 sessions SSH vers des hôtes différents, le temps d’authentification cumulé devient mesurable.
Ed25519, en revanche, utilise des clés compactes et un algorithme de signature plus léger. L’établissement de session est en moyenne 30 % plus rapide qu’avec RSA 4096. Sur un pipeline qui déclenche 20 déploiements par jour, ce n’est pas anecdotique : ce sont des minutes cumulées pendant lesquelles un bug de performance reste en production sans correctif.
Ce que j’applique aujourd’hui : une paire Ed25519 dédiée au pipeline de production, générée avec un commentaire explicite via l’option -C. Trop de fichiers authorized_keys contiennent des clés sans libellé, où plus personne ne sait à quoi correspond AAAAC3Nza... ni si on peut la supprimer sans casser le déploiement.
Le fichier authorized_keys : les trois erreurs qui font échouer un rollout sans laisser de trace exploitable
La première erreur est une ligne vide ou un caractère parasite. Le fichier authorized_keys ne tolère pas les fins de ligne Windows, ni les espaces insérés accidentellement. Un développeur qui ouvre le fichier sous Notepad sur un poste Windows, ajoute sa clé, puis repasse par un outil de provisionnement : le démon SSH refuse toutes les clés situées après la ligne corrompue. Je l’ai vu trois fois en deux ans.
La deuxième erreur est le commentaire invalide. La syntaxe est simple : ssh-ed25519 AAAA... commentaire_optionnel. Pas de chevrons, pas de barres obliques dans le commentaire, pas de retour à la ligne manuel inséré par l’éditeur. Une clé tronquée sur deux lignes est silencieusement ignorée. Le démon passe à la ligne suivante sans journaliser quoi que ce soit d’exploitable.
La troisième erreur est le droit d’accès trop permissif. Le démon SSH est intransigeant : si ~/.ssh/authorized_keys a des permissions 664 au lieu de 600, il l’ignore. Même sanction pour le dossier ~/.ssh. Ce n’est pas un paramètre optionnel. Si tu provisionnes tes clés via Ansible ou Terraform, ajoute toujours une tâche de vérification des permissions en post-installation.
Ces trois erreurs partagent un symptôme commun : aucun message utile dans les logs applicatifs. Le CI renvoie un Permission denied (publickey) et tu passes 20 minutes à vérifier que ta clé privée est chargée, au lieu d’inspecter le format du fichier distant.
⚠️ Attention : Le démon SSH lit
authorized_keysde haut en bas et s’arrête à la première clé correspondant à l’algorithme proposé. Si deux clés de même type existent pour le même utilisateur, seule la première est testée. La deuxième est ignorée.
Le test qui t’évite 30 minutes de debug
stat -c %a ~/.ssh/authorized_keys
Si le retour n’est pas 600, ton déploiement échouera silencieusement un jour. Vérifier cette permission prend 3 secondes. La négliger coûte un rollout bloqué. Tu choisis.
SSH agent forwarding en CI/CD : la fausse bonne idée
Le scénario classique : ton pipeline GitHub Actions doit atteindre le serveur de staging via un bastion. Plutôt que de provisionner une clé sur le bastion, tu actives le SSH agent forwarding. La connexion est relayée, ta clé locale sert à rebondir. Élégant sur le papier.
Deux problèmes concrets. D’abord, la sécurité : le bastion peut techniquement utiliser ta clé le temps que la session persiste. Si le bastion est compromis, un attaquant signe des connexions vers tous les serveurs où cette clé est autorisée. C’est le risque documenté du ForwardAgent yes, et il ne se matérialise pas uniquement dans les scénarios de menace théoriques.
Ensuite, la fiabilité. L’agent forwarding ajoute un maillon au tunnel d’authentification. Si le socket de l’agent n’est pas joignable dans le conteneur CI, si le service SSH a un timeout mal configuré, le pipeline échoue avec une erreur qui n’a rien à voir avec le code déployé. Tu vas inspecter le build, les tests unitaires, le bundle, alors que le coupable est une variable SSH_AUTH_SOCK mal positionnée.
La méthode que j’applique désormais : une clé SSH dédiée par environnement, provisionnée avec un scope limité, sans agent forwarding. Le fichier authorized_keys du serveur cible mentionne uniquement la clé du pipeline autorisé à pousser sur cet environnement. C’est plus de configuration initiale, mais quand le déploiement échoue, l’enquête commence par l’authentification, pas par le code.
Vérifier ta configuration SSH avant qu’elle ne bloque un déploiement urgent
Un correctif de gestion d’état React avec Zustand qui ramène un CLS de 0.18 à 0.02 ne sert à rien s’il reste coincé dans un runner sans accès SSH au serveur. La vérification de l’infrastructure d’authentification doit faire partie du runbook de déploiement standard.
La checklist en trois commandes que j’exécute à chaque mise en place d’un nouveau pipeline :
ssh -T -i ~/.ssh/deploy_key [email protected]
ssh -o ConnectTimeout=5 user@production-server "echo OK"
ssh user@production-server "stat -c %a ~/.ssh/authorized_keys"
La première valide que la clé est enregistrée sur le gestionnaire de source. La deuxième teste la connectivité vers le serveur cible avec un timeout court, pour ne pas bloquer le pipeline si le réseau ralentit. La troisième confirme que les permissions du fichier authorized_keys sont correctes.
Si tu génères tes scripts de déploiement via un IDE comme Cursor ou avec un assistant type Claude Code, ne laisse jamais une suggestion copier une clé privée en dur dans un fichier de configuration. Les chemins de clés en dur finissent dans les dépôts. Utilise les secrets de ton gestionnaire CI, toujours.
Ces trois vérifications intégrées à un script de health check pré-déploiement éliminent le scénario catastrophe : un bug en production, un fix prêt, et aucun moyen de le déployer parce que la clé a changé sans que personne ne l’ait documenté.
Rotation des clés SSH : la méthode qui ne coupe jamais l’accès
Une paire de clés SSH a une durée de vie. Les recommandations de sécurité suggèrent une rotation tous les 6 à 12 mois. Le piège : supprimer l’ancienne clé avant que la nouvelle soit propagée partout, et se retrouver exclu de son propre serveur.
La méthode fiable : déploiement progressif. Génére la nouvelle paire, ajoute la clé publique dans le fichier authorized_keys de la cible, puis déploie la nouvelle clé privée dans les secrets du pipeline. Fais cohabiter les deux clés pendant 24 heures. Une fois que les déploiements passent avec la nouvelle clé de manière stable, retire l’ancienne.
Ce cycle en deux temps est exactement celui qu’on applique aux tokens API et aux variables d’environnement critiques. Aucune raison de ne pas l’appliquer aux clés SSH, à part l’habitude tenace de considérer le SSH comme une couche système immuable. Ce n’est pas le cas : c’est un composant actif de ton pipeline de performance, avec un état, une date de validité, et un impact direct sur le MTTR.
Questions fréquentes
Peut-on utiliser la même paire de clés SSH pour plusieurs projets ?
Techniquement oui, et certains le font par simplicité. Le problème apparaît quand un projet est compromis ou qu’un membre de l’équipe quitte l’organisation. Révoquer une clé partagée coupe l’accès à tous les projets simultanément. Une clé par environnement de production reste le standard raisonnable, même si cela demande un peu plus de discipline dans la gestion des secrets.
Ed25519 est-il compatible avec tous les serveurs ?
Ed25519 est supporté par OpenSSH depuis la version 6.5, sortie en 2014. Tout serveur Linux maintenu à jour le supporte sans exception. Si tu hérites d’un serveur très ancien ou d’un appliance exécutant une version antérieure, bascule sur ECDSA avec la courbe P-256. Évite RSA pour les nouvelles clés, sauf contrainte de compatibilité explicitement documentée.
Comment auditer qui a accès à mes serveurs via SSH ?
La méthode la plus fiable est un audit régulier du fichier authorized_keys sur chaque serveur. Un script qui parse chaque ligne, extrait le commentaire, et le compare à un registre interne des clés autorisées fait le travail. Les clés sans commentaire ou avec un libellé inconnu sont à investiguer en priorité. Cet audit devrait être aussi fréquent que la revue des accès aux dépôts Git ou aux consoles cloud.