Vendredi 23 novembre 2018

Créer une paire de clés publique / privée pour SSH

La plupart des sessions SSH sont authentifiées à l’aide d’un mot de passe. Seulement, ce mode d’authentification a plusieurs inconvénients :

Il faut mémoriser son mot de passe, idéalement, un par serveur si on se soucie un minimum de la sécurité ;
Il faut le changer régulièrement, toujours dans un souci de sécurité ;
Il faut le saisir à chaque connexion ;
En cas d’attaque man-in-the-middle, le mot de passe est compromis.

L’authentification par clé asymétrique permet de s’affranchir de tout cela. Les clés sont générées par paire : une clé publique que l’on peut diffuser librement, et une clé privée associée que l’on doit garder bien secrètement. Voici quelques avantages qu’elles procurent :

Avec l’utilisation d’un agent, on peut conserver la passphrase en mémoire et éviter de la saisir à chaque connexion, pratique aussi pour des scripts, voir l’article utiliser keychains ;
Plusieurs clés publiques peuvent être assignées à un utilisateur, pratique pour des personnes se partageant un même compte root ;
Changer de passphrase ne se fait qu’une fois sur sa clé privée, contrairement aux mots de passe qui doivent être changés sur chaque serveur ;
La paire de clés est générée aléatoirement contrairement à un mot de passe qui n’est souvent pas aléatoire ;
Le serveur ne reçoit ni votre passphrase, ni votre clé privée, mais une réponse à un challenge mathématique, donc une connexion sur un serveur compromis ne compromet pas votre clé privée ;
Les clés sont extrêmement difficiles à casser.

Pré requis

Le serveur doit accepter la connexion par clé. La ligne PubKeyAuthentication yes doit être présente dans le fichier de configuration du serveur, généralement /etc/ssh/sshd_config. Générer la paire de clés

On utilise pour cela la commande ssh-keygen. J’utilise ici une clé RSA de 8196 bits. Oui, c’est énorme, mais au moins, je suis tranquille quelques années.

L’option -C permet de spécifier un commentaire sur sa clé, j’aime bien savoir à quel utilisateur correspond une clé, donc je l’indique ici, c’est une bonne habitude à prendre.

L’option -f permet d’indiquer le nom de la clé privée à générer. C’est également une bonne pratique de générer ses clés dans son répertoire ~/.ssh/.

La génération des clés peut prendre plusieurs minutes. La clé privée doit être protégée par un long mot de passe : une passphrase. Elle doit comporter plusieurs mots, la phrase peut même avoir un sens, tant qu’elle n’est pas écrite sur un post-it, la clé est bien protégée. Le clé privée doit également être sur une machine verrouillée lorsque vous n’êtes pas devant l’écran et elle ne doit être lisible que par vous, afin d’éviter que d’autres utilisateurs du système puissent y avoir accès. Si vous oubliez votre passphrase, il n’y a aucun moyen de la récupérer.

on crée le répertoire au cas où il n’existe pas

mkdir -p ~/.ssh/

seul le propriétaire peut lire et écrire dans ce répertoire

chmod 0700 ~/.ssh/

on génère la clé

ssh-keygen -t rsa -b 8196 -C “ordi perso matthieu” -f ~/.ssh/ma_cle_perso

on saisit deux fois sa passphrase, rien ne s’affiche, c’est normal.

on a maintenant notre paire de clés

ls -l ~/.ssh/ma_cle_perso* -rw——- 1 matthieu staff 6446 2 oct 22:40 /Users/matthieu/.ssh/ma_cle_perso -rw-r–r– 1 matthieu staff 1420 2 oct 22:40 /Users/matthieu/.ssh/ma_cle_perso.pub

Le dossier ~/.ssh/ contient la clé privée ma_cle_perso et sa clé publique correspondante ma_cle_perso.pub. Installer sa clé publique

Pour autoriser la connexion à un serveur via sa clé privée, il faut au préalable ajouter le contenu de la clé publique correspondante dans le fichier ~/.ssh/authorized_keys de l’utilisateur distant.

Ici, je souhaite installer ma clé ~/.ssh/ma_cle_perso.pub sur le compte matthieu de la machine monserveur.local. Lors de l’installation de la clé publique, le mot de passe du compte sera bien évidemment demandé. Installer sa clé publique avec ssh-copy-id

Si la commande ssh-copy-id est présente sur votre machine, génial, cette commande sert justement à installer sa clé publique sur un compte distant.

ssh-copy-id -i .ssh/ma_cle_perso.pub matthieu@monserveur.local

le mot de passe distant vous sera demandé afin de pouvoir installer la clé

Installer sa clé publique sans ssh-copy-id

Si la commande ssh-copy-id n’existe pas, on utilisera cette longue commande à la place.

ssh matthieu@monserveur.local ‘mkdir -p ~/.ssh; chmod 0700 ~/.ssh; echo ‘ $(< ~/.ssh/ma_cle_perso.pub) ‘ » ~/.ssh/authorized_keys ; chmod 0600 ~/.ssh/authorized_keys’

Tester la connexion par clé

Une fois la clé publique installée, on peut tester que cette méthode d’authentification fonctionne.

on peut ensuite tester la connexion avec la clé et sa passphrase

ssh -i ~/.ssh/ma_cle_perso matthieu@monserveur.local

on n’a plus qu’à saisir sa passphrase

Si vous ne voulez pas saisir à chaque connexion votre passphrase, allez faire un tour sur l’article utiliser keychains. Envoyer sa clé publique à un administrateur

Il peut arriver qu’on ne puisse pas installer directement sa clé sur une machine et qu’on doive la donner à un administrateur afin qu’il l’installe lui-même sur le serveur. Il est possible que la clé soit interceptée et remplacée par celle d’une personne malintentionnée. Ainsi, la bonne pratique consiste à vérifier par téléphone avec son interlocuteur que la clé publique reçue par email est bien celle envoyée, en vérifiant par exemple sa somme de contrôle SHA256.

Alors que vous êtes au téléphone, chacun de son côté saisit la commande suivante, afin de vérifier que l’empreinte SHA256 n’a pas changé pendant le voyage.

ssh-keygen -E sha256 -lf ~/.ssh/ma_cle_perso.pub 8196 SHA256:PYdgMViJ7OrcL8bVBV0aAsJkglFS7w9xDazNAMxWd84 mon ordi perso (RSA)

Durant cet appel, l’administrateur pourrait également vous dicter l’empreinte du serveur afin que vous puissiez la vérifier lors de la première connexion. Changer sa passphrase

Si on souhaite changer sa passphrase, rien de plus simple, on saisit la commande suivante. L’ancienne passphrase nous est d’abord demandée, ensuite on saisit deux fois la nouvelle.

ssh-keygen -p -f ~/.ssh/ma_cle_perso

C’est tout, même pas besoin de redéployer sa clé publique. Que faire si la clé privée est compromise ?

Si vous avez opté pour une clé privée sans passphrase et que vous pensez que quelqu’un a récupéré votre clé privée, votre clé privée est compromise. Il faut toujours mettre une passphrase sur vos clés privées, je vous l’ai dit au début de cet article.

Si quelqu’un a vu votre passphrase, votre clé privée peut potentiellement être compromise si l’individu a réussi à récupérer le fichier contenant la clé privée. Si vous pensez que ce n’est pas le cas, votre clé n’est pas compromise. Allez vite changer votre passphrase. Si vous pensez qu’il a réussi à récupérer le fichier, alors votre clé est compromise.

Si vous pensez que quelqu’un a récupéré le fichier contenant votre clé privée, et que celle-ci est protégée par une passphrase, en théorie, elle n’est pas compromise. Sur un serveur géré par un administrateur, votre clé privée peut être lue par root, mais elle est protégée par sa passphrase, et de toutes façons, vous faites confiance à l’administrateur, non ? Une personne malintentionnée pourrait finir par trouver la passphrase via une attaque brute force mais pas avant plusieurs années.

En cas de compromission de la clé privée, que faut-il faire ?

Regénérer une nouvelle paires de clés ;
Redéployer la nouvelle clé publique sur tous les serveurs ;
Révoquer la clé publique sur tous les serveurs où elle est présente, c’est-à-dire supprimer la ligne correspondant à votre clé publique dans le fichier ~/.ssh/authorized_keys et en même temps vérifier que d’autres clés publiques non légitimes n’ont pas été ajoutées ;
Si la clé publique était présente sur un compte root, il va falloir faire un audit complet du serveur car il peut potentiellement avoir été compromis, bonne chance.

J’utilise personnellement plusieurs clés privées, une (ou plusieurs) par machine et serveur personnels, une au travail, une sur mon téléphone, etc. Ceci me permet de révoquer finement une clé publique si je considère que la clé privée correspondante a pu être compromise. De plus, toutes les clés n’ont pas forcément accès aux mêmes machines, par exemple, au travail, je ne veux pas pouvoir accéder à mes serveurs personnels, il me suffit de ne pas installer ma clé publique travail sur ces machines.

Installer SSH keychain pour éviter d’avoir à saisir ses passphrases

Lorsqu’on a plusieurs clés SSH et que l’on souhaite éviter de saisir sans arrêt sa passphrase, keychain est la solution. Cet outil permet de gérer les clés SSH (et GPG mais ce n’est pas le sujet) de façon très pratique et sécurisée. Il agit en tant que frontal aux commandes ssh-agent et ssh-add. Contrairement à ssh-agent qui fonctionne sur une session (du login à la déconnexion), keychain conserve un agent fonctionnel tant que le serveur n’a pas été redémarré. Ceci diminue le nombre de fois où vous devrez saisir votre passphrase. De plus, il est facile d’utiliser l’agent dans un script exécuté par cron. Installation

On utilise le gestionnaire de paquets sous Linux, et sous MacOS on utilisera Homebrew.

sur un système Linux Debian

apt-get install keychain

sur un MacOS

brew install keychain

Ensuite, on édite notre fichier ~/.bash_profile pour y ajouter le contenu suivant.

eval keychain --eval --agents ssh ~/.ssh/neptune_key ~/.ssh/ma_cle_perso

On indique ici que l’on utilise la commande eval via l’option –eval, ceci permet de ne pas se soucier du SHELL que l’on exécute. On n’utilise que la partie SSH de l’agent –agents ssh et on indique les clés à déverrouiller en argument.

Si vous ne savez pas comment utiliser les clés SSH, vous pouvez aller faire un tour sur l’article créer vos clés publique et privée SSH. Première ouverture du terminal

La première fois que j’ouvre mon terminal, keychain sait qu’aucune clé SSH n’est chargée, alors il demande les passphrases de chacune des clés. Si deux clés ont la même passphrase, à priori, keychain ne demande la passphrase qu’une seule fois, c’est mon cas dans cet exemple.

  • keychain 2.8.3 ~ http://www.funtoo.org
  • Starting ssh-agent…
  • Adding 2 ssh key(s): /Users/matthieu/.ssh/neptune_key /Users/matthieu/.ssh/ma_cle_perso Enter passphrase for /Users/matthieu/.ssh/neptune_key:
  • ssh-add: Identities added: /Users/matthieu/.ssh/neptune_key /Users/matthieu/.ssh/ma_cle_perso

Sessions de terminal suivantes

Lorsque j’ouvre d’autres sessions de mon terminal, keychain indique que des clés sont chargées, il ne redemande donc pas les passphrases.

  • keychain 2.8.3 ~ http://www.funtoo.org
  • Found existing ssh-agent: 33235
  • Known ssh key: /Users/matthieu/.ssh/neptune_key
  • Known ssh key: /Users/matthieu/.ssh/ma_cle_perso

Dans le cas où l’agent est exécuté sur un serveur, la passphrase ne sera demandé qu’après un reboot. Se connecter à un serveur SSH

La connexion se fait de manière classique, on spécifie simplement la clé à utiliser. La passphrase ne doit pas être demandée si la clé privée correspondante est chargée en mémoire.

ssh -i ~/.ssh/neptune_key matthieu@monserveur.local

Lister les clés chargées

Cette commande liste les signatures des clés chargées en mémoire.

keychain –list SHA256:zz7Jx7tHoUpCdAAMSRXU7nl+zmbYdKeO9oYmQfsUg2s SHA256:PYdgMViJ7OrcL8bVBV0aAsJkglFS7w9xDazNAMxWd84

Utiliser depuis un script via cron

Si j’ai un script qui est exécuté par cron (le crontab de ma session), et que ce script doit se connecter à un serveur distant, pour faire une sauvegarde par exemple, voici comment utiliser keychain dans le script.

#!/bin/bash

chemin vers la clé privée à utiliser

SSH_PRIVATE_KEY=~/.ssh/ma_cle_perso

l’empreinte de la clé

SSH_KEY_FINGERPRINT=ssh-keygen -E sha256 -lf "$SSH_PRIVATE_KEY" | cut -d\ -f2

chargement de keychain en mode silencieux

eval keychain --quiet --agents ssh --noask --eval "$SSH_PRIVATE_KEY"

vérification que la clé privée est bien chargée dans keychain

if keychain –list | grep $SSH_KEY_FINGERPRINT > /dev/null; then

# on déroule notre script ici.

# exemple, on veut lister le répertoire distant de monserveur.local
LS=`ssh -i "$SSH_PRIVATE_KEY" matthieu@monserveur.local ls` else
printf "Erreur, clé %s non chargée...\n" "$SSH_PRIVATE_KEY" >&2

# envoyer un email pour prévenir l'utilisateur, par exemple fi

L’option –noask indique à keychain qu’il ne doit pas demander la passphrase, étant donné qu’il s’agit d’un script exécuté sans intervention humaine, personne ne sera là pour la saisir si la clé privée est verouillée. On teste ensuite que notre clé est bien chargée en mémoire, pour cela on calcule son empreinte, puis on vérifie si elle est dans la liste des clés chargées. Décharger les clés en mémoire

Si on doit laisser quelqu’un utiliser son ordinateur quelques minutes, on ne veut pas que cette personne puisse se connecter à un de nos serveurs. On doit donc décharger les clés en mémoire.

keychain –clear

  • keychain 2.8.3 ~ http://www.funtoo.org
  • Found existing ssh-agent: 33235
  • ssh-agent: All identities removed.

Sur un serveur distant, afin d’améliorer la sécurité de keychain, on peut utiliser cette option dans le .bash_profile. Ainsi, on prend pour hypothèse que chaque nouvelle session SSH est considérée comme étant initiée par un intrus, l’intrus doit donc prouver qu’il est un utilisateur légitime en saisissant la passphrase, même si la clé était déjà en mémoire auparavant. Les scripts lancés par cron pourront toujours s’exécuter lorsque vous vous déconnecterez, sauf si un intrus s’est réellement connecté, et dans ce cas, la passphrase n’aura pas été saisie.

Sur un serveur, il est courant de mettre cette ligne dans le fichier ~/.bash_profile.

eval keychain --eval --clear --agents ssh ~/.ssh/neptune_key ~/.ssh/ma_cle_perso

Un point sur la sécurité

Utiliser un agent SSH a une incidence sur la sécurité, voici ce qu’il faut savoir.

Ne copiez pas votre clé privée sur un serveur non administré par vous, si vous le faites, vous partagez votre clé avec l’administrateur, la passphrase protège normalement votre clé, mais si vous avez copié votre clé privée, c’est que vous l’avez sans doute utilisée, vous avez donc partagé votre passphrase avec l’administrateur, même si cette opération n’est pas simple à réaliser, on peut se demander si la clé privée est compromise, à partir de cet instant. Ne stockez vos clés privées que sur des machines dites de confiance, encore mieux, ne lancez vos sessions SSH que depuis votre ordinateur personnel.
N’utilisez l’agent SSH ou l’agent forwarding que sur des machines administrées par vous car ces deux méthodes créent des variables d’environnement SSH_AUTH_SOCK contenant une socket vers l’agent SSH, il suffit à l’administrateur de mettre le chemin vers cette socket dans la variable d’environnement SSH_AUTH_SOCK de sa propre session pour avoir accès à toutes vos machines, sans mot de passe.

Concernant ce dernier point, on pourra ajouter ceci dans notre fichier ~/.ssh/config pour interdire l’agent forwarding.

Host * ForwardAgent no

Diminuer le temps de connexion à un serveur SSH

Établir une nouvelle connexion SSH ne prend en général que quelques secondes. Si on doit se connecter plusieurs fois au même serveur, ces secondes s’ajoutent et ça finit, en ce qui me concerne, par être ennuyeux. Sont impactés, tous les services utilisant SSH, par exemple, git, svn, rsync, etc.

Une solution assez méconnue de SSH consiste à réutiliser une connexion déjà établie, ce qui signifie que l’on n’a qu’une seule phase d’authentification et que les connexions suivantes vers un même serveur sont quasi instantanées.

Pour ce faire, rien de plus simple, on édite son fichier ~/.ssh/config et on ajoute au début du fichier les lignes suivantes.

Host * ControlMaster auto ControlPath ~/.ssh/sockets/%r@%h-%p ControlPersist 3600

Puis on crée le dossier ~/.ssh/sockets/.

mkdir ~/.ssh/sockets chmod 700 ~/.ssh/sockets

Voici les explications de la configuration, ligne par ligne.

Host *

Ceci signifie que les paramètres suivants vont pouvoir s’appliquer sur tous les serveurs sur lesquels on va se connecter. On peut restreindre un domaine en utilisant, par exemple, Host *.chezmoi.fr.

ControlMaster auto

Le paramètre ControlMaster indique à SSH de réutiliser une connexion déjà existante vers un serveur si elle existe déjà. En se connectant deux fois au même serveur, la deuxième connexion est plus rapide car l’authentification ainsi que la connexion TCP sont déjà faites. Les deux connexions utilisent le multiplexage.

ControlPath ~/.ssh/sockets/%r@%h-%p

Le paramètre ControlPath indique à SSH où aller stocker et chercher les fichiers de type socket sur le disque.

ControlPersist 3600

Le paramètre ControlPersist indique que le fichier de type socket doit être valide 3600 secondes, dans notre cas. Ceci autorise par exemple de fermer toutes les connexions puis de se reconnecter immédiatement. Cela permet aussi d’éviter des déconnexions brutales dans le cas où la première connexion SSH serait fermée.

Plus d’informations en faisant un man ssh_config.