Aller au contenu principal

Clés d'hôte SSH

Avant de se connecter au serveur, un job doit savoir à quel serveur il parle : c'est le rôle des clés d'hôte, rangées dans ~/.ssh/known_hosts.

Par défaut : balayage du serveur​

Sans rien configurer, chaque job balaie le serveur (ssh-keyscan) et croit les clés qu'il présente. Deux limites :

  • Aucune vérification : un autre serveur qui répondrait à la place du vôtre serait accepté, à chaque job.
  • Des connexions sans authentification, en nombre : un balayage ouvre une connexion par type de clé, et chaque job en lance un. Sur un pipeline de plusieurs dizaines de jobs, un serveur récent (OpenSSH 9.8 et suivants, PerSourcePenalties) peut finir par refuser les connexions du runner, y compris celles des déploiements.

Le job signale ce mode par un avertissement :

ATTENTION : aucune clé d'hôte fournie (SSH_KNOWN_HOSTS ou SSH_KNOWN_HOSTS_FILE) :
ATTENTION : balayage de serveur.fr, donc confiance au premier contact.

Fournir les clés d'hôte (depuis 0.4.32)​

Relever les clés​

Depuis un poste qui connaît déjà le serveur, et en comparant le résultat à ce que ce poste a déjà dans son known_hosts :

ssh-keyscan -p 22 serveur.fr
# À comparer avec les clés déjà connues du poste :
ssh-keygen -F serveur.fr

Avec un port différent de 22, ssh-keyscan -p 2222 serveur.fr écrit les lignes sous la forme attendue, [serveur.fr]:2222 ssh-ed25519 ….

Les donner au projet​

Au choix :

  • SSH_KNOWN_HOSTS : une variable CI qui contient ces lignes. Elle peut être de type « Variable » ou « File ». Les clés d'hôte sont publiques, la variable n'a pas à être masquée.
  • SSH_KNOWN_HOSTS_FILE : le chemin d'un fichier versionné dans le projet, relatif à sa racine. Un changement de clé passe alors par une revue.
variables:
SSH_KNOWN_HOSTS_FILE: .gitlab/ssh_known_hosts

Si les deux sont définies, SSH_KNOWN_HOSTS l'emporte.

Ce qui change alors​

  • Plus aucun balayage : seules les clés fournies sont crues.
  • Vérification stricte : le job écrit StrictHostKeyChecking yes dans ~/.ssh/config. Une connexion à un serveur absent de la liste, ou dont la clé a changé, est refusée. Si un job se connecte à plusieurs serveurs, il faut donc fournir les clés de chacun.
  • SSH_KNOWN_HOSTS_FILE introuvable ou vide : le job échoue, il ne revient pas au balayage.

Contrôles faits par le job (depuis 0.4.33)​

Une fois les clés installées, le job vérifie avant toute connexion :

  • Que la vérification stricte est effective. Le bloc StrictHostKeyChecking yes est écrit en tête de ~/.ssh/config (pour ssh, la première valeur lue l'emporte), puis le job interroge ssh lui-même (ssh -G). Si la réponse n'est pas stricte, il échoue :

    ERREUR : la vérification stricte des clés d'hôte n'est pas effective pour serveur.fr
  • Que le serveur visé figure dans les clés fournies, sous la forme [serveur.fr]:2222 ou serveur.fr. Les entrées hachées et les motifs (*.serveur.fr) sont reconnus. Sinon :

    ERREUR : aucune clé d'hôte pour serveur.fr (port 2222) dans SSH_KNOWN_HOSTS_FILE (.gitlab/ssh_known_hosts).
    ERREUR : SSH_HOST ou SSH_PORT ont-ils changé sans que les clés fournies soient mises à jour ?
  • Qu'une variable définie n'est pas vide. SSH_KNOWN_HOSTS ou SSH_KNOWN_HOSTS_FILE définie mais vide fait échouer le job au lieu de ramener au balayage. Pour revenir au balayage, supprimer la variable.

Ces contrôles portent sur SSH_HOST et SSH_PORT. Ils ne voient pas :

  • une option passée sur la ligne de commande, par exemple -o StrictHostKeyChecking=no dans SSH_CHAIN : elle l'emporte sur tout fichier de configuration ;
  • les autres serveurs qu'un job joindrait.

Le contrôle de présence utilise ssh-keygen. S'il manque dans l'image, le job le signale par un ATTENTION et continue.

attention

Quand la clé d'hôte du serveur change (réinstallation, migration), les jobs échouent tant que la variable ou le fichier n'a pas été mis à jour. C'est le but recherché.

Projets qui redéfinissent .ssh​

Un projet qui redéfinit .ssh ou son before_script ne profite pas de ce comportement. Il peut le reprendre par !reference [.ssh-known-hosts, script], après avoir créé ~/.ssh.