Mode opératoire — Les clés SSH : comprendre, créer, déployer, gérer

Document autonome et universel. Partie 1 théorique, parties suivantes applicables à Linux, macOS et Windows. Les exemples s’appuient sur l’infrastructure sio.internal mais la méthode vaut partout.

Dernière mise à jour : 01/10/2026


Sommaire

§Contenu
1Théorie — pourquoi une clé plutôt qu’un mot de passe
2Comment ça marche réellement : le défi-réponse
3Les deux familles de clés qu’on confond toujours
4Choisir l’algorithme · la phrase de passe
5Générer une clé — Linux · macOS · Windows
6Déployer la clé publique — et le piège Windows
7L’agent SSH — saisir sa phrase de passe une seule fois
8~/.ssh/config — le fichier qui change tout
9Le serveur de rebond (bastion / jump host) et ProxyJump
10Durcir le serveur
11Confiner une clé à une seule commande
12Cycle de vie : inventaire, rotation, révocation
13Les 8 pièges rencontrés · checklist par système

1 · Théorie — pourquoi une clé plutôt qu’un mot de passe

1.1 Le problème du mot de passe

   AUTHENTIFICATION PAR MOT DE PASSE
   ─────────────────────────────────
   Le client ENVOIE le secret au serveur, qui le vérifie.
                    ▲
        le secret QUITTE ta machine à chaque connexion
FaiblesseConséquence
Le secret voyageil existe, à chaque connexion, ailleurs que chez toi
Le serveur le connaîtun serveur compromis récupère ton mot de passe
Il est devinable8 à 12 caractères mémorisables = quelques milliards de possibilités
Il est rejouablequi l’obtient peut se connecter indéfiniment
Il est testable à distanced’où les attaques par force brute, et les sshguard pour s’en défendre

1.2 Ce que la clé change

   AUTHENTIFICATION PAR CLÉ
   ────────────────────────
   Le client PROUVE qu'il détient le secret, sans jamais le transmettre.
                    ▲
          la clé privée ne quitte JAMAIS ta machine
PropriétéEffet
Le secret ne circule pasun serveur compromis n’apprend rien d’exploitable
256 bits d’entropieindevinable en pratique — pas de force brute possible
Deux facteurs si phrase de passeavoir le fichier et savoir la phrase
Révocable individuellementon retire une clé sans toucher aux autres

La même logique que unix_socket sous MariaDB, ou qu’une carte à puce. On remplace « connais-tu le secret ? » par « peux-tu prouver que tu le détiens ? ». C’est la différence entre montrer sa clé et la donner.


2 · Comment ça marche réellement

2.1 Deux clés mathématiquement liées

   ssh-keygen produit UNE PAIRE
   ────────────────────────────
   id_ed25519       clé PRIVÉE   → reste chez toi, ne sort jamais
   id_ed25519.pub   clé PUBLIQUE → se copie partout, sans risque

Ce qui est chiffré ou signé avec l’une ne peut être vérifié qu’avec l’autre. On ne peut pas retrouver la privée à partir de la publique — c’est le fondement de la cryptographie asymétrique.

La clé publique n’est pas un secret. On peut la publier, l’envoyer par courriel, la coller dans un ticket. Elle ne permet que de vérifier, jamais de se faire passer pour toi. C’est d’ailleurs ce que fait GitHub : https://github.com/<pseudo>.keys expose publiquement les clés de chacun.

2.2 Le dialogue, étape par étape

   CLIENT                                    SERVEUR
     │                                          │
     │  « je suis ipfixe, voici l'empreinte    │
     │    de la clé que je veux utiliser »     │
     │ ───────────────────────────────────────►│
     │                                          │ cherche cette empreinte
     │                                          │ dans ~/.ssh/authorized_keys
     │                                          │
     │  ◄─────────────────────────────────────  │ « trouvée. Signe ceci. »
     │       un défi aléatoire                  │      (nombre aléatoire)
     │                                          │
     │  signe le défi avec la clé PRIVÉE       │
     │ ───────────────────────────────────────►│
     │                                          │ vérifie la signature
     │                                          │ avec la clé PUBLIQUE
     │  ◄─────────────────────────────────────  │
     │            accès accordé                 │

À aucun moment la clé privée n’est transmise. Le serveur n’apprend rien qu’il pourrait rejouer : le défi est différent à chaque connexion.

C’est pourquoi une clé publique volée est sans valeur. Elle permet de vérifier une signature, pas d’en produire une.


3 · Les deux familles de clés — ne jamais les confondre

C’est la confusion la plus fréquente, et elle rend les messages d’erreur incompréhensibles.

   CLÉ D'UTILISATEUR                    CLÉ D'HÔTE
   ─────────────────                    ──────────
   « qui suis-je ? »                    « à qui je parle ? »

   le CLIENT prouve son identité        le SERVEUR prouve la sienne

   ~/.ssh/id_ed25519       (privée)     /etc/ssh/ssh_host_ed25519_key      (privée)
   ~/.ssh/id_ed25519.pub   (publique)   /etc/ssh/ssh_host_ed25519_key.pub  (publique)

   vérifiée via                         vérifiée via
   ~/.ssh/authorized_keys               ~/.ssh/known_hosts
   sur le serveur                       sur le client
SymptômeFamille concernée
Permission denied (publickey)clé d’utilisateur — le serveur ne te reconnaît pas
REMOTE HOST IDENTIFICATION HAS CHANGED!clé d’hôte — le serveur n’est plus celui que tu connaissais
The authenticity of host … can't be establishedclé d’hôte — première rencontre

3.1 Pourquoi les clés d’hôte comptent

Elles protègent de l’usurpation de serveur. Sans elles, un intercepteur pourrait se placer entre toi et la machine visée, recueillir ce que tu tapes, et relayer.

Conséquence directe pour le clonage de VM : deux machines clonées partagent leurs clés d’hôte. L’une peut donc se faire passer pour l’autre sans que SSH ne détecte quoi que ce soit. C’est la régénération la moins optionnelle après un clonage — voir MO-1-Clonage-VM.md §3.2.

sudo rm -f /etc/ssh/ssh_host_* && sudo dpkg-reconfigure openssh-server

3.2 known_hosts — le modèle « confiance à la première rencontre »

À la première connexion, le client affiche l’empreinte et demande confirmation. Une fois acceptée, elle est enregistrée — et toute divergence ultérieure déclenche une alerte.

ssh-keygen -F 10.0.20.11              # l'entrée est-elle présente ?
ssh-keygen -R 10.0.20.11              # la supprimer (après un légitime changement)
ssh-keyscan -H 10.0.20.11 >> ~/.ssh/known_hosts   # l'ajouter d'avance

ssh-keyscan est indispensable pour l’automatisation. Un démon — lsyncd, une sauvegarde, un déploiement — ne peut pas répondre à la question « voulez-vous continuer ? ». Il faut enregistrer l’empreinte avant de le lancer.

Mais ssh-keyscan accepte ce qu’il trouve, sans vérifier. Sur un réseau de confiance c’est acceptable ; en environnement sensible, l’empreinte se vérifie par un canal séparé (console de l’hyperviseur, par exemple).


4 · Choisir l’algorithme et la phrase de passe

4.1 Quel algorithme

TypeVerdictPourquoi
ed25519 par défautrapide, clé courte (68 caractères), aucun paramètre à choisir donc rien à se tromper, résistant aux implémentations bancales
rsa 4096 compatibilitépour du matériel ancien qui ignore ed25519. Clé longue, plus lente
ecdsa évitercourbes NIST aux paramètres contestés, et implémentations historiquement fragiles
dsa interditretiré d’OpenSSH, cassé
ssh-keygen -t ed25519 -C "axel@lenovo-2026"

-C est un commentaire libre, stocké en clair à la fin de la clé publique. Il n’a aucun rôle cryptographique mais tout un rôle d’inventaire : c’est lui qu’on lit dans un authorized_keys pour savoir à qui appartient une clé. Un format utile : utilisateur@machine-annee ou usage-machine.

4.2 La phrase de passe

   SANS phrase de passe                 AVEC phrase de passe
   ────────────────────                 ────────────────────
   1 facteur : AVOIR le fichier         2 facteurs : AVOIR + SAVOIR
   vol du disque = accès total          vol du disque = rien d'exploitable
   utilisable par un démon              nécessite un agent (§7)
UsageRecommandation
Ta clé personnelle d’administration phrase de passe obligatoire + agent
Clé de service (sauvegarde, synchronisation)sans phrase, mais confinée par command= — voir §11

La règle : une clé sans phrase de passe se justifie uniquement si elle est enfermée dans une action précise sur une machine précise. Une clé sans phrase et sans restriction, c’est un mot de passe en clair dans un fichier.

Changer la phrase d’une clé existante — sans régénérer la clé :

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

5 · Générer une clé

5.1 Linux et macOS

ssh-keygen -t ed25519 -C "axel@lenovo-2026"
QuestionRéponse
Enter file in which to save the keyEntrée pour le défaut, ou un chemin dédié
Enter passphraseune vraie phrase — elle ne s’affiche pas pendant la frappe

5.2 Windows 10 / 11 / Server 2019+

OpenSSH est intégré depuis Windows 10 1809 — rien à installer pour le client.

ssh-keygen -t ed25519 -C "axel@poste-windows-2026"

Les fichiers atterrissent dans C:\Users\<toi>\.ssh\.

Le serveur SSH, lui, n’est pas installé par défaut sous Windows :

Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
Start-Service sshd
Set-Service -Name sshd -StartupType Automatic

Les deux dernières commandes sont nécessaires : Start-Service démarre maintenant, Set-Service rend le démarrage automatique. Sans la seconde, l’accès est perdu au prochain redémarrage.

Et par défaut, une session SSH Windows ouvre cmd.exe. Pour obtenir PowerShell :

New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -PropertyType String -Force

5.3 Les fichiers produits et leurs droits

FichierContenuDroits Linux/macOS
id_ed25519 clé privée600
id_ed25519.pubclé publique644
~/.ssh/le répertoire700
~/.ssh/authorized_keysclés autorisées à entrer600
~/.ssh/known_hostsempreintes des serveurs connus644
chmod 700 ~/.ssh && chmod 600 ~/.ssh/id_ed25519 ~/.ssh/authorized_keys 2>/dev/null

SSH refuse d’utiliser une clé privée trop permissive et affiche UNPROTECTED PRIVATE KEY FILE!. Ce n’est pas un excès de zèle : sur une machine partagée, un fichier lisible par tous annule tout l’intérêt de la clé.

Vérifier l’empreinte d’une clé :

ssh-keygen -lf ~/.ssh/id_ed25519.pub

6 · Déployer la clé publique

6.1 Linux et macOS — ssh-copy-id

ssh-copy-id -i ~/.ssh/id_ed25519.pub [email protected]

L’outil se connecte une dernière fois par mot de passe, ajoute la clé à authorized_keys, et pose les bons droits tout seul. C’est la méthode à privilégier.

6.2 Sans ssh-copy-id — la méthode manuelle

cat ~/.ssh/id_ed25519.pub | ssh [email protected] "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"

Ne JAMAIS copier-coller une clé à la main depuis un terminal. Une clé publique fait une ligne d’environ 100 caractères ; un terminal la replie à l’affichage, et le collage réintroduit ces retours à la ligne. La clé devient invalide sans aucun message d’erreur — l’authentification échoue simplement.

(Piège rencontré dans ce TP lors de la mise en place de l’accès SSH à pfSense.)

Le contrôle qui tranche : authorized_keys doit contenir une ligne par clé.

wc -l ~/.ssh/authorized_keys

6.3 Windows — le piège des comptes administrateurs

C’est la particularité Windows, et elle fait perdre des heures.

   Compte STANDARD          →  C:\Users\<nom>\.ssh\authorized_keys
   Compte ADMINISTRATEUR    →  C:\ProgramData\ssh\administrators_authorized_keys
                                ▲
                    fichier COMMUN à tous les administrateurs

Si le compte appartient au groupe Administrateurs, OpenSSH ignore son authorized_keys personnel et ne lit que le fichier commun.

# depuis le client, envoyer la clé
Get-Content $env:USERPROFILE\.ssh\id_ed25519.pub | ssh admin@10.0.40.100 "powershell -Command `"Add-Content -Path C:\ProgramData\ssh\administrators_authorized_keys -Value ([Console]::In.ReadToEnd())`""

Puis, sur la machine Windows, corriger les droits — sans quoi le fichier est ignoré :

icacls C:\ProgramData\ssh\administrators_authorized_keys /inheritance:r /grant "SYSTEM:F" /grant "Administrateurs:F"

Seuls SYSTEM et Administrateurs doivent y avoir accès. OpenSSH vérifie ces droits et refuse silencieusement le fichier s’ils sont plus larges. Aucun message côté client : on tombe simplement sur la demande de mot de passe.

Le diagnostic, côté serveur Windows :

Get-Content C:\ProgramData\ssh\logs\sshd.log -Tail 20

(activer le journal détaillé via LogLevel DEBUG3 dans C:\ProgramData\ssh\sshd_config)

6.4 Vérifier que ça fonctionne

ssh -o PreferredAuthentications=publickey -o BatchMode=yes [email protected] true ; echo "code : $?"

0 = la clé fonctionne seule. Ces options interdisent le repli sur le mot de passe : sans elles, un succès pourrait masquer un échec de la clé.


7 · L’agent SSH

7.1 Le problème qu’il résout

Une clé protégée par phrase de passe la réclame à chaque connexion. L’agent la garde déchiffrée en mémoire pour la durée de la session.

   sans agent : phrase saisie à CHAQUE connexion  →  tentation de retirer la phrase
   avec agent : phrase saisie UNE FOIS par session

L’agent est ce qui rend la phrase de passe supportable — et donc ce qui la rend réellement utilisée. Un mécanisme de sécurité pénible finit toujours par être contourné.

7.2 Linux

eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
ssh-add -l          # lister les clés chargées

Pour éviter de le relancer à chaque terminal, la plupart des bureaux démarrent un agent automatiquement. Sinon, ajouter à ~/.bashrc :

[ -z "$SSH_AUTH_SOCK" ] && eval "$(ssh-agent -s)" > /dev/null

7.3 macOS — intégration au Trousseau

ssh-add --apple-use-keychain ~/.ssh/id_ed25519

Et dans ~/.ssh/config, pour que ce soit automatique :

Host *
    UseKeychain yes
    AddKeysToAgent yes
    IdentityFile ~/.ssh/id_ed25519

UseKeychain est propre à macOS : la phrase est stockée dans le Trousseau du système et rechargée à l’ouverture de session. Sur Linux ou Windows, cette directive provoque une erreur de configuration — d’où l’intérêt de la placer dans un fichier propre au Mac.

7.4 Windows

Le service existe mais est désactivé par défaut :

Set-Service ssh-agent -StartupType Automatic
Start-Service ssh-agent
ssh-add $env:USERPROFILE\.ssh\id_ed25519
ssh-add -l

L’agent Windows stocke les clés dans le registre, chiffrées par DPAPI — liées à ta session Windows. Elles survivent donc au redémarrage, contrairement à l’agent Linux. Pratique, mais cela signifie qu’une session Windows compromise donne accès aux clés : raison de plus pour verrouiller sa session.


8 · ~/.ssh/config — le fichier qui change tout

C’est le fichier le plus rentable de SSH, et le plus ignoré des débutants.

# ~/.ssh/config          (C:\Users\<toi>\.ssh\config sous Windows)

Host *
    AddKeysToAgent      yes
    ServerAliveInterval 60
    ServerAliveCountMax 3

Host pfsense
    HostName     10.0.30.1
    User         admin
    IdentityFile ~/.ssh/id_lab

Host web1
    HostName     10.0.10.10
    User         ipfixe
    IdentityFile ~/.ssh/id_lab

Host mysql1 mysql2 mysql3
    User         ipfixe
    IdentityFile ~/.ssh/id_lab

Host mysql1
    HostName     10.0.20.10
Host mysql2
    HostName     10.0.20.11
Host mysql3
    HostName     10.0.20.12

# Rebond : joindre une machine interne via le bastion
Host interne-*
    User         ipfixe
    IdentityFile ~/.ssh/id_lab
    ProxyJump    bastion

Host bastion
    HostName     10.0.30.12
    User         ipfixe
    IdentityFile ~/.ssh/id_lab

Dès lors : ssh web1 suffit.

DirectiveRôle
HostNamel’adresse réelle — l’alias n’est qu’un raccourci
IdentityFilequelle clé utiliser pour cet hôte
ProxyJump rebondir par une machine intermédiaire, en une seule commande — détaillé au §9
ServerAliveIntervalenvoie un signal toutes les 60 s — évite les coupures d’inactivité
AddKeysToAgentcharge la clé dans l’agent à la première utilisation

8.1 Deux pièges classiques — tous deux rencontrés dans ce TP

1 · Une directive sans valeur casse tout le fichier

Host web1
    User

→ Bad configuration option et tout le fichier est ignoré, y compris les blocs valides. Une directive vide n’est pas « neutre », c’est une erreur de syntaxe.

2 · Le fichier s’applique à l’alias, pas à l’adresse

ssh web1              #  IdentityFile appliqué
ssh [email protected] #  aucun bloc ne correspond → clé par défaut

SSH compare le nom écrit sur la ligne de commande aux motifs Host. Écrire l’adresse IP court-circuite la configuration.

Pour contourner ponctuellement : ssh -F /dev/null … ignore le fichier, ssh -v … affiche quel bloc est appliqué. Le mode verbeux est l’outil de diagnostic numéro un de SSH :

ssh -v web1 2>&1 | grep -iE "identity file|offering|authentications"

9 · Le serveur de rebond (bastion / jump host)

9.1 Le problème qu’il résout

Une infrastructure correctement cloisonnée n’expose aucune de ses machines internes. Mais il faut bien les administrer. Deux mauvaises réponses, et la bonne :

RéponseConséquence
Ouvrir le port 22 de chaque serveur depuis l’extérieurautant de portes que de machines, autant de services sshd à surveiller et à durcir
Ouvrir une redirection de port par serveur sur le pare-feumême chose, en plus confus — et la traçabilité est perdue
Une seule machine joignable, par laquelle tout passeune porte, un journal, une politique

Cette machine s’appelle un bastion (ou jump host, ou serveur de rebond). C’est la seule que le pare-feu autorise en entrée ; toutes les autres ne sont joignables que depuis elle.

                   ┌──────────────── zone exposée ────────────────┐
   administrateur ─┤  22/tcp  ►  BASTION                          │
                   └──────────────────┬───────────────────────────┘
                                      │ 22/tcp — autorisé
                   ┌──────────────────▼─── zone interne ──────────┐
                   │   srv-web-01   srv-mysql-01   srv-ha   …     │
                   │   (injoignables depuis l'extérieur)          │
                   └──────────────────────────────────────────────┘

Le bastion n’est pas une protection magique. Il ne rend pas les serveurs internes plus sûrs : il réduit la surface d’attaque à une seule machine, qu’on peut alors durcir et surveiller sérieusement. Tout l’intérêt est là — et toute la responsabilité aussi : qui compromet le bastion atteint tout le reste.

9.2 Les trois façons de rebondir — seule la troisième est canonique

1 · Se connecter au bastion, puis relancer ssh depuis lui

ssh bastion                       # première session
ssh [email protected]             # seconde session, lancée DEPUIS le bastion

Ça marche, et c’est ce que tout le monde fait au début. Mais :

  • la clé privée doit être sur le bastion — ou alors on retape un mot de passe ;
  • scp et rsync deviennent pénibles : il faut copier en deux temps ;
  • le bastion accumule des clés privées. S’il tombe, toutes tombent avec lui.

2 · Le transfert d’agent (ssh -A, ForwardAgent yes)

L’idée : ne pas poser la clé sur le bastion, mais laisser le bastion utiliser l’agent du poste client à distance.

ssh -A bastion
ssh [email protected]     # utilise la clé restée sur le poste client

La clé privée ne quitte effectivement jamais le poste. Mais :

Le transfert d’agent crée une socket sur le bastion. Toute personne disposant de root sur cette machine peut s’en servir pour s’authentifier en votre nom, partout où votre clé est acceptée, tant que la session est ouverte. C’est précisément pour cela que authorized_keys propose l’option no-agent-forwarding (voir §11), et que la documentation OpenSSH le déconseille.

Retenir : -A n’est acceptable que vers une machine dont on a la pleine maîtrise — et il n’est de toute façon plus nécessaire depuis ProxyJump.

3 · ProxyJump — la version canonique

ssh -J bastion [email protected]

ou, mieux, écrit une fois pour toutes dans ~/.ssh/config :

Host bastion
    HostName     10.0.30.12
    User         ipfixe
    IdentityFile ~/.ssh/id_lab

Host mysql1
    HostName     10.0.20.10
    User         ipfixe
    IdentityFile ~/.ssh/id_lab
    ProxyJump    bastion

Dès lors, une seule commande suffit :

ssh mysql1

Ce qui se passe réellement — et c’est tout l’intérêt :

  poste client                    bastion                  mysql1
      │                              │                        │
      ├──── 1. session SSH ─────────►│                        │
      │     (authentifiée par ma clé)    │                        │
      │                              │                        │
      ├──── 2. demande un tunnel TCP ►├──── vers 10.0.20.10:22 ►│
      │                              │   (le bastion ne fait   │
      │                              │    QUE relayer des      │
      │                              │    octets chiffrés)     │
      │                              │                        │
      ├══════ 3. seconde session SSH, de bout en bout ════════►│
      │        chiffrée entre le poste et mysql1               │
ConséquencePourquoi c’est décisif
La clé privée reste sur le poste clientle bastion n’en détient aucune
Le bastion ne déchiffre rienil relaye un flux chiffré de bout en bout
Pas de socket d’agent exposéecontrairement à -A
La clé d’hôte de mysql1 est vérifiée par le clientl’authentification du serveur reste intacte

Avec ProxyJump, le bastion est un relais réseau, pas un intermédiaire de confiance. Il voit *qu’*une connexion a lieu, et vers où — pas ce qui y transite. C’est exactement le niveau de confiance qu’on veut lui accorder.

9.3 Ce que ProxyJump rend possible gratuitement

Tout ce qui s’appuie sur SSH en hérite, sans configuration supplémentaire :

scp fichier.sql mysql1:/tmp/          # copie directe, à travers le bastion
rsync -av dossier/ mysql1:/srv/       # idem
sftp mysql1
ssh mysql1 'systemctl status mariadb' # commande distante

Plusieurs rebonds s’enchaînent avec une virgule :

ssh -J bastion1,bastion2 serveur-final

9.4 Deux clés, ou une seule ?

Question légitime : faut-il la même clé pour le bastion et pour les serveurs internes ?

ApprocheQuand la choisir
Une clé unique id_lablaboratoire, petite infrastructure — c’est ce qu’on fait ici
Deux clés distinctesproduction : une clé n’ouvre que le bastion, une autre n’est acceptée que par les serveurs internes. Compromettre le poste client reste nécessaire pour les deux, mais la révocation devient granulaire

Le principe de §12.1 reste le même : une clé par origine, pas une clé recopiée partout.

9.5 Appliqué à l’infrastructure sio.internal

Dans ce TP, srv-docker (10.0.30.12, VLAN 30 — ADM) joue le rôle de bastion :

ÉlémentValeur
Machinesrv-docker · 10.0.30.12
Alias pare-feuSRV_BASTION
Ports autorisés vers luiPORTS_BASTION — 22 et 3389
Ports autorisés depuis luiadministration des VLAN 10 et 20

Bloc ~/.ssh/config correspondant, à placer sur le poste d’administration :

Host bastion
    HostName     10.0.30.12
    User         ipfixe
    IdentityFile ~/.ssh/id_lab

Host web1 web2 ha mysql1 mysql2 mysql3
    User         ipfixe
    IdentityFile ~/.ssh/id_lab
    ProxyJump    bastion

Host web1
    HostName 10.0.10.10
Host web2
    HostName 10.0.10.11
Host ha
    HostName 10.0.10.5
Host mysql1
    HostName 10.0.20.10
Host mysql2
    HostName 10.0.20.11
Host mysql3
    HostName 10.0.20.12

Validation

ssh -v mysql1 2>&1 | grep -iE "proxy|connecting to"

La trace doit montrer une connexion au bastion, puis l’établissement de la session vers 10.0.20.10. Et sur le bastion, aucune clé privée ne doit apparaître :

ssh bastion 'ls -l ~/.ssh/'

→ authorized_keys et known_hosts uniquement. Aucun fichier id_* sans extension.

Dans ce TP, Tailscale court-circuite le bastion : le poste ag-lenovo joint directement les VLAN par le routeur de sous-réseaux. C’est pratique, et c’est exactement la dette T-6 relevée dans la documentation — le tailnet est une zone de confiance qui contourne le cloisonnement. Le rebond par bastion est la méthode canonique ; Tailscale est le raccourci qu’on s’autorise en laboratoire, en le sachant.


10 · Durcir le serveur

Une fois les clés en place et testées, on ferme le mot de passe.

/etc/ssh/sshd_config — ou un fragment dans /etc/ssh/sshd_config.d/10-durcissement.conf :

PasswordAuthentication          no
KbdInteractiveAuthentication    no
PermitRootLogin                 prohibit-password
PubkeyAuthentication            yes
AllowGroups                     sshusers
MaxAuthTries                    3
LoginGraceTime                  30
DirectiveEffet
PasswordAuthentication no supprime la force brute par construction
KbdInteractiveAuthentication noferme la voie détournée du clavier interactif
PermitRootLogin prohibit-passwordroot par clé uniquement — no si un compte sudo suffit
AllowGroupsseuls les membres du groupe peuvent se connecter
MaxAuthTries 3limite les essais par connexion
sudo sshd -t && sudo systemctl reload ssh

sshd -t avant tout rechargement, et garder une session ouverte pendant le test. Une erreur de configuration SSH sur une machine distante, c’est une machine perdue jusqu’au prochain accès console. Même réflexe que apache2ctl configtest, haproxy -c ou php -l.

Le filet de sécurité : la console de l’hyperviseur — Proxmox, VMware, iDRAC. Elle ne dépend ni de SSH ni du pare-feu. Un accès de secours ne doit jamais dépendre du système qu’il secourt.

10.1 Ce que le durcissement rend inutile

Une fois PasswordAuthentication no en place, les protections anti-force-brute (fail2ban, sshguard, Login Protection de pfSense) n’ont plus grand-chose à défendre : il n’y a plus de mot de passe à deviner.

Mais elles restent actives et peuvent te bloquer toi, si un client retente en boucle une authentification vouée à l’échec — par exemple un mot de passe périmé resté dans la configuration d’un client. C’est exactement ce qui s’est produit dans ce TP (incident H-13) : trois échecs suffisaient, et chaque blocage durait 1,5 fois plus longtemps que le précédent.

La leçon : après tout changement d’identifiants, passer en revue les endroits où l’ancien secret est encore stocké — clients SSH, gestionnaires de mots de passe, scripts, supervision.


11 · Confiner une clé à une seule commande

Le motif le plus utile pour l’automatisation : une clé qui ne peut faire qu’une chose.

command="/usr/bin/rrsync -wo /var/www/wordpress/wp-content",no-agent-forwarding,no-port-forwarding,no-pty,no-user-rc,no-X11-forwarding ssh-ed25519 AAAAC3Nza… lsyncd
OptionInterdit
command="…" toute commande autre que celle-ci
no-ptyl’ouverture d’un terminal interactif
no-port-forwardingd’utiliser la connexion comme tunnel
no-agent-forwardingde rebondir avec les clés du client
no-X11-forwardingle relais graphique

Le test qui prouve le confinement :

ssh -i ~/.ssh/id_lsyncd [email protected]
PTY allocation request failed on channel 0        ← no-pty
/usr/bin/rrsync error: Not invoked via sshd       ← command="…"

Une clé root qui ne donne aucun accès root. Le privilège appartient à la commande forcée, pas au compte. Motif réutilisable pour toute automatisation : sauvegardes, supervision, déploiements, synchronisation.

SSH_ORIGINAL_COMMAND contient la commande réellement demandée par le client. Un script de confinement maison peut la lire pour n’autoriser qu’un jeu précis d’actions :

case "$SSH_ORIGINAL_COMMAND" in
  "backup-now") /usr/local/bin/backup.sh ;;
  *) echo "Commande non autorisee" ; exit 1 ;;
esac

12 · Cycle de vie : inventaire, rotation, révocation

12.1 Une clé par origine, pas une clé pour tout

    MAUVAIS                       BON
   ─────────                      ──────
   une clé recopiée sur           une clé par machine d'origine
   toutes tes machines            + une clé par automatisation
        │                              │
   un vol = tout révoquer         un vol = révoquer une seule clé
   impossible de savoir           le commentaire dit d'où elle vient
   laquelle a fuité

Le commentaire -C porte l’inventaire : axel@lenovo-2026, lsyncd-web01-vers-web02, sauvegarde-nocturne.

12.2 Faire l’inventaire

Sur chaque serveur :

sudo find /home /root -name authorized_keys -exec sh -c 'echo "== $1"; cat "$1"' _ {} \;

Sous Windows :

Get-Content C:\ProgramData\ssh\administrators_authorized_keys

Une clé oubliée dans un authorized_keys est une porte ouverte permanente. Les clés n’expirent pas toutes seules — contrairement aux mots de passe soumis à une politique de renouvellement. L’inventaire périodique est la seule parade.

12.3 Révoquer

Retirer la ligne correspondante de l’authorized_keys :

ssh-keygen -lf ~/.ssh/id_ed25519.pub          # obtenir l'empreinte
sudo sed -i '/AAAAC3NzaC1lZDI1NTE5AAAAI.../d' ~/.ssh/authorized_keys

La révocation est immédiate et locale : pas d’autorité centrale à prévenir, pas de liste à publier. C’est à la fois la force du modèle (simplicité) et sa faiblesse (il faut penser à le faire sur chaque serveur).

12.4 Quand renouveler

ÉvénementAction
Départ d’une personnerévoquer sa clé partout
Poste perdu ou volérévoquer, régénérer, redéployer
Machine clonée régénérer les clés d’hôte — voir MO-1
Réinstallation d’un serveurprévenir les clients : l’empreinte d’hôte change
Rotation périodiquetous les 1 à 2 ans pour une clé personnelle

13 · Pièges et checklists

13.1 Les huit pièges rencontrés dans ce TP

#SymptômeCauseCorrection
1Permission denied (publickey)clé non déployée, ou mauvaise clé proposéessh -v pour voir laquelle est offerte
2Clé refusée sans message clairclé collée sur plusieurs lignes depuis un terminalwc -l authorized_keys → doit valoir 1 par clé
3Demande de phrase à chaque connexionagent non lancé ou clé non chargéessh-add · §7
4Bad configuration option, toute la config ignoréedirective sans valeur dans ~/.ssh/configcorriger la ligne fautive
5IdentityFile ignoréconnexion par adresse IP et non par l’aliasutiliser l’alias, ou ajouter un bloc Host
6Timeout, puis blocages de plus en plus longssshguard — un mot de passe périmé dans un clientvider le champ · liste blanche · H-13
7Clé générée pour www-data : inutilisableson interpréteur est /usr/sbin/nologinutiliser un compte avec shell + command=
8REMOTE HOST IDENTIFICATION HAS CHANGED après clonageclés d’hôte dupliquéesrégénérer sur le clone · MO-1

13.2 Checklist — nouvelle VM Linux

   Serveur SSH installé et activé
   Clés d'hôte régénérées SI la machine est un clone
   Clé publique déployée (ssh-copy-id de préférence)
   Droits : ~/.ssh 700 · authorized_keys 600 · clé privée 600
   Connexion par clé testée AVANT de fermer le mot de passe
   PasswordAuthentication no  +  sshd -t  +  reload
   Bloc ajouté dans ~/.ssh/config côté client
   Empreinte enregistrée (ssh-keyscan) si un automate doit s'y connecter

13.3 Checklist — nouvelle machine Windows

   Add-WindowsCapability OpenSSH.Server
   Start-Service sshd  ET  Set-Service -StartupType Automatic
   DefaultShell = PowerShell (optionnel mais recommandé)
   Règle de pare-feu OpenSSH-Server-In-TCP active (créée automatiquement)
    Compte ADMIN → C:\ProgramData\ssh\administrators_authorized_keys
    icacls : SYSTEM et Administrateurs UNIQUEMENT
   Service ssh-agent passé en Automatic si on utilise une phrase de passe

13.4 Checklist — poste client (Linux, macOS, Windows)

   Une clé ed25519, avec phrase de passe, commentaire explicite
   Agent configuré (Trousseau sur macOS, service sur Windows)
   ~/.ssh/config avec un bloc par hôte
   ProxyJump configuré si l'accès passe par un bastion
   Sauvegarde de la clé privée dans un coffre — PAS sur un partage réseau
   Inventaire : savoir où chaque clé est déployée

À retenir en une phrase : une clé SSH remplace « connaître un secret » par « prouver qu’on le détient » — et tout le travail d’administration consiste à savoir, à tout moment, quelle clé ouvre quelle porte.