Ubuntu 24.04 : durcissement SSH qui ne vous enfermera pas — checklist pragmatique

Cet article vous a aidé ?

Tout le monde aime le « durcissement » jusqu’à la première fois que vous appliquez un changement, rechargez sshd et réalisez que vous venez de bloquer votre seul accès distant. La machine tourne toujours. Vous le sentez. Mais vous n’y avez plus accès. Ce n’est pas de la sécurité ; c’est un temps d’arrêt auto-infligé.

Ceci est un guide de durcissement SSH orienté production pour Ubuntu 24.04 qui suppose que vous voulez une authentification plus robuste, une surface d’attaque réduite et une meilleure traçabilité — sans jouer votre accès à une seule modification. Nous prendrons volontairement la voie la moins spectaculaire : modifications étagées, commandes de vérification et plans de retour.

Principes de durcissement qui évitent les verrouillages

Le durcissement SSH est un exercice de fiabilité déguisé en tâche de sécurité. L’objectif n’est pas la « paranoïa maximale ». L’objectif est le « minimum de regrets ». Voici les principes qui vous gardent en poste :

  • Ne changez jamais SSH en une seule étape. Étalez les changements. Validez. Puis appliquez.
  • Gardez un second chemin d’accès. Une seconde session SSH, un utilisateur différent, une méthode d’authentification différente, ou un accès console (IPMI/KVM/console série cloud). De préférence deux.
  • Testez la config avant de recharger. Utilisez sshd -t et affichez la configuration effective pour confirmer ce qui va se produire.
  • Utilisez des blocs « Match » pour limiter le périmètre de risque. Appliquez des paramètres stricts pour la majorité des utilisateurs, gardez un utilisateur break-glass contraint mais fonctionnel.
  • Verrouillez le réseau d’abord, puis renforcez l’authentification. Réduire qui peut atteindre SSH est plus sûr que de deviner quels clients pourront encore négocier vos nouveaux paramètres cryptographiques.
  • Mesurez avant d’ajuster. Si vous ne savez pas quelles méthodes d’authentification sont utilisées aujourd’hui, vous êtes sur le point de casser quelqu’un d’important à 2 h du matin.

Une citation à retenir : « L’espoir n’est pas une stratégie. » — Gene Kranz. Courte, un peu dure, et exacte en opérations.

Blague n°1 : Modifier sshd_config un vendredi est un excellent moyen d’apprendre à quel point votre rotation d’astreinte est efficace.

Faits intéressants et contexte historique (parce que ça explique les valeurs par défaut actuelles)

  1. SSH a remplacé largement Telnet parce que Telnet envoyait les identifiants en clair. Ce n’était pas « un peu peu sûr » ; c’était « Wireshark est votre gestionnaire de mots de passe ».
  2. OpenSSH est né comme un fork libre de SSH en 1999. Ce fork est devenu l’outil d’accès distant par défaut sur la plupart des systèmes Unix-like parce qu’il était ouvert, audité et… ennuyeux — dans le bon sens.
  3. Le port 22 n’est pas magique. C’est juste le défaut assigné par l’IANA. Le déplacer réduit le bruit des scans de masse, pas les attaques ciblées, et peut compliquer les pare-feu et les outils.
  4. Les versions du protocole SSH ont été un vrai problème jadis. SSH‑1 est obsolète ; SSH‑2 est la norme. Les Ubuntu/OpenSSH modernes désactivent déjà les mauvais comportements du passé.
  5. La connexion root était historiquement pratique pour les admins. Elle rendait aussi l’audit atroce et transformait chaque identifiant fuit en compromission totale. C’est pourquoi « pas de root sur SSH » est devenu un conseil courant.
  6. Les algorithmes faibles ont été dépréciés pour de bonnes raisons. DSA est quasiment un objet de musée. RSA est toujours présent mais de plus en plus encadré ; Ed25519 est devenu populaire car rapide, solide et difficile à mal utiliser.
  7. Des paramètres cryptographiques stricts peuvent casser l’automatisation ancienne. Certains clients embarqués et bibliothèques legacy ne supportent pas les combos KEX/MAC modernes. Ce n’est pas de votre faute, mais c’est votre incident si vous basculez sans inventaire.
  8. Les attaques par force brute ne sont pas devenues plus nombreuses ; elles sont devenues moins chères. Le balayage à l’échelle cloud a rendu « authentification par mot de passe sur un SSH exposé à Internet » une stratégie perdante à terme.

Base : savoir ce que vous exécutez et qui peut y accéder

Le durcissement commence par une base. Vous devez savoir :

  • Quelle version du serveur OpenSSH vous exécutez (ensemble de fonctionnalités, valeurs par défaut, directives disponibles).
  • Sur quel(s) port(s) vous écoutez et sur quelles interfaces.
  • Quelles méthodes d’authentification sont utilisées actuellement.
  • Quels réseaux peuvent atteindre SSH.
  • Comment récupérer l’accès si vous faites une erreur.

Sur Ubuntu 24.04, openssh-server est typiquement géré par systemd (ssh.service) et configuré par /etc/ssh/sshd_config plus des fragments drop-in sous /etc/ssh/sshd_config.d/ (si vous choisissez de les utiliser). L’approche « drop-in » est plus propre pour le contrôle des changements : vous pouvez garder une base minimale, conviviale pour le fournisseur, et gérer votre propre fragment.

Tâches pratiques (commandes + sens de la sortie + décisions)

Voici des tâches réelles que vous pouvez exécuter sur Ubuntu 24.04. Chacune inclut : la commande, ce que vous devriez voir, et la décision à en tirer. C’est le cœur du « durcissement sans verrouillage » : vous ne changez jamais ce que vous n’avez pas observé.

Task 1: Confirm OpenSSH server is installed and versioned

cr0x@server:~$ dpkg -l | grep -E '^ii\s+openssh-server'
ii  openssh-server  1:9.6p1-3ubuntu13  amd64  secure shell (SSH) server, for secure access from remote machines

Ce que cela signifie : Vous exécutez OpenSSH 9.6p1 packagé pour Ubuntu. La version compte pour les directives supportées et les valeurs par défaut cryptographiques.

Décision : Si openssh-server n’est pas installé ou est anormalement ancien, arrêtez-vous et corrigez cela avant le « durcissement ». Durcir un démon périmé, c’est polir une serrure rouillée.

Task 2: Check whether SSH is running and how it started

cr0x@server:~$ systemctl status ssh --no-pager
● ssh.service - OpenBSD Secure Shell server
     Loaded: loaded (/usr/lib/systemd/system/ssh.service; enabled; preset: enabled)
     Active: active (running) since Mon 2025-12-30 09:14:22 UTC; 2h 18min ago
       Docs: man:sshd(8)
             man:sshd_config(5)
   Main PID: 1247 (sshd)
      Tasks: 1 (limit: 18962)
     Memory: 6.3M
        CPU: 1.221s
     CGroup: /system.slice/ssh.service
             └─1247 "sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups"

Ce que cela signifie : Le service est actif et géré par systemd. Le PID et l’invocation sont visibles.

Décision : S’il n’est pas en cours, ne le « durcissez » pas — restaurez d’abord la santé du service. Sur un hôte sans console, vous voulez SSH stable avant d’éditer quoi que ce soit.

Task 3: Identify listening port(s) and interfaces

cr0x@server:~$ ss -tulpn | grep -E 'sshd|:22'
tcp   LISTEN 0      128          0.0.0.0:22        0.0.0.0:*    users:(("sshd",pid=1247,fd=3))
tcp   LISTEN 0      128             [::]:22           [::]:*    users:(("sshd",pid=1247,fd=4))

Ce que cela signifie : SSH écoute sur toutes les interfaces IPv4 et IPv6 sur le port 22.

Décision : Si c’est un hôte exposé à Internet, vous êtes probablement sur-exposé. Planifiez des restrictions réseau (pare-feu + listes d’autorisation) et éventuellement lier à une interface de gestion.

Task 4: See effective sshd configuration (not just the file)

cr0x@server:~$ sudo sshd -T | egrep -i 'port |listenaddress|passwordauthentication|pubkeyauthentication|permitrootlogin|authenticationmethods'
port 22
listenaddress 0.0.0.0
listenaddress ::
permitrootlogin prohibit-password
passwordauthentication yes
pubkeyauthentication yes
authenticationmethods any

Ce que cela signifie : C’est la configuration que sshd utilisera effectivement après avoir lu tous les includes et les valeurs par défaut.

Décision : Vous durcissez à partir de la configuration effective, pas de vos suppositions. Si PasswordAuthentication yes, vous devez planifier de le désactiver en toute sécurité (après avoir confirmé les clés et l’automatisation).

Task 5: Validate your current config syntax before touching anything

cr0x@server:~$ sudo sshd -t

Ce que cela signifie : L’absence de sortie est bonne. Une sortie indique des erreurs de syntaxe et sshd refuserait de démarrer/recharger.

Décision : Si vous voyez des erreurs ici, ne rechargez pas sshd. Corrigez la syntaxe d’abord. Les erreurs de syntaxe sont le générateur de verrouillage le plus pur.

Task 6: Confirm you have a working key-based login (from another terminal)

cr0x@server:~$ ssh -o PreferredAuthentications=publickey -o PasswordAuthentication=no -v ops@127.0.0.1 'echo OK'
OpenSSH_9.6p1 Ubuntu-3ubuntu13, OpenSSL 3.0.13 30 Jan 2024
debug1: Authenticating to 127.0.0.1:22 as 'ops'
debug1: Authentication succeeded (publickey).
OK

Ce que cela signifie : Vous pouvez vous authentifier avec une clé et vous refusez explicitement le recours au mot de passe.

Décision : Si cela échoue, ne désactivez pas encore l’authentification par mot de passe. Corrigez d’abord les clés, l’agent ou le fichier authorized_keys.

Task 7: Inspect authorized_keys permissions (silent killers)

cr0x@server:~$ sudo ls -ld /home/ops /home/ops/.ssh /home/ops/.ssh/authorized_keys
drwxr-x---  6 ops ops 4096 Dec 30 09:01 /home/ops
drwx------  2 ops ops 4096 Dec 30 09:03 /home/ops/.ssh
-rw-------  1 ops ops  742 Dec 30 09:03 /home/ops/.ssh/authorized_keys

Ce que cela signifie : Les permissions semblent correctes : le home n’est pas inscriptible par le monde, .ssh est 700, authorized_keys n’est pas inscriptible par les autres.

Décision : Si vous voyez des bits inscriptibles par le groupe/le monde ou une mauvaise propriété, corrigez-les. sshd ignore les clés qu’il juge non sécurisées, et il ne vous fera pas la fête pour vous prévenir.

Task 8: Confirm which users are allowed and which groups matter

cr0x@server:~$ getent group sudo
sudo:x:27:ops,deploy

Ce que cela signifie : ops et deploy sont dans sudo ; ce sont probablement des utilisateurs administratifs interactifs.

Décision : Si vous prévoyez d’utiliser AllowGroups, assurez-vous de savoir quels groupes autoriser. Mal circonscrire cela est un classique « pourquoi je ne peux pas me connecter ? ».

Task 9: Check firewall state and existing SSH allowances

cr0x@server:~$ sudo ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW IN    10.20.0.0/16
22/tcp                     ALLOW IN    192.168.50.0/24

Ce que cela signifie : UFW est actif, par défaut refuser les entrantes, et SSH n’est autorisé que depuis deux réseaux privés.

Décision : C’est bien. Si vous voyez 22/tcp ALLOW IN Anywhere sur un hôte internet, corrigez le pare-feu avant d’ajuster la crypto.

Task 10: Observe auth events and brute-force noise

cr0x@server:~$ sudo journalctl -u ssh --since "2 hours ago" | tail -n 12
Dec 30 10:44:01 server sshd[8621]: Failed password for invalid user admin from 203.0.113.77 port 51244 ssh2
Dec 30 10:44:06 server sshd[8621]: Failed password for invalid user admin from 203.0.113.77 port 51244 ssh2
Dec 30 10:44:10 server sshd[8621]: Connection closed by invalid user admin 203.0.113.77 port 51244 [preauth]
Dec 30 11:02:33 server sshd[9012]: Accepted publickey for ops from 10.20.8.41 port 49912 ssh2: ED25519 SHA256:2d3v...

Ce que cela signifie : Vous avez des tentatives de force brute par mot de passe (probablement exposition Internet ou VPN) et des connexions légitimes par clé.

Décision : Si vous voyez des tentatives de mot de passe répétées, désactiver l’authentification par mot de passe devient une priorité plus élevée. Si vous ne voyez que des connexions par clé, vous pouvez appliquer des règles d’authentification plus strictes avec moins de risque.

Task 11: Check current SSH client compatibility (from your workstation)

cr0x@server:~$ ssh -G ops@server | egrep -i 'kexalgorithms|ciphers|macs|hostkeyalgorithms' | head
ciphers chacha20-poly1305@openssh.com,aes128-gcm@openssh.com,aes256-gcm@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr
macs umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com
kexalgorithms sntrup761x25519-sha512@openssh.com,curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256
hostkeyalgorithms ssh-ed25519,ecdsa-sha2-nistp256,rsa-sha2-512,rsa-sha2-256

Ce que cela signifie : Votre client supporte des algorithmes modernes, incluant des options KEX hybrides post-quantiques (approche d’OpenSSH) et Ed25519.

Décision : Avant de resserrer les algorithmes du serveur, inventairez la compatibilité des clients. Le fait que votre poste de travail soit moderne ne signifie pas que votre flotte d’automatisation l’est aussi.

Task 12: Create a safe “sshd on a different port” canary (temporary)

cr0x@server:~$ sudo /usr/sbin/sshd -D -p 2222 -o PermitRootLogin=no -o PasswordAuthentication=no -o PubkeyAuthentication=yes

Ce que cela signifie : Cela démarre un sshd au premier plan sur le port 2222 avec des paramètres d’authentification stricts, sans toucher votre démon principal.

Décision : Utilisez ceci pour tester de nouvelles politiques tout en gardant le port 22 comme filet de sécurité. Une fois validé, transposez les paramètres dans la config et rechargez le service réel.

Task 13: Test reload safely (after changes) and confirm it took effect

cr0x@server:~$ sudo sshd -t && sudo systemctl reload ssh && sudo sshd -T | egrep -i 'passwordauthentication|permitrootlogin'
passwordauthentication no
permitrootlogin no

Ce que cela signifie : La syntaxe est valide, le reload a réussi, et la configuration effective montre maintenant une authentification plus stricte.

Décision : Si le reload échoue, ne paniquez pas — vos sessions existantes devraient rester actives. Corrigez, puis rechargez à nouveau. Si vous avez fait un redémarrage et que le service n’est pas revenu, vous êtes en « mode console ». Évitez les redémarrages sauf si nécessaire.

Task 14: Confirm you didn’t accidentally block yourself at the network layer

cr0x@server:~$ sudo ufw status numbered
Status: active

     To                         Action      From
[ 1] 22/tcp                     ALLOW IN    10.20.0.0/16
[ 2] 22/tcp                     ALLOW IN    192.168.50.0/24

Ce que cela signifie : Vous voyez clairement quelles règles s’appliquent et dans quel ordre.

Décision : Si vous êtes sur le point de resserrer les règles, ajoutez d’abord de nouvelles règles d’autorisation, testez la connectivité, puis supprimez les anciennes règles larges. Les modifications de pare-feu par soustraction sont la façon dont vous découvrez que votre VPN n’émet pas depuis le sous-réseau que vous pensiez.

sshd_config : réglages à changer (et ceux qui font mal)

Ubuntu 24.04 + OpenSSH sont déjà corrects. L’astuce est de choisir des changements qui réduisent matériellement le risque sans détoner l’accès. Voici ce que je recommande et pourquoi, plus les modes d’échec.

Use a drop-in file, not a messy monolith

Créez un fragment géré comme /etc/ssh/sshd_config.d/50-hardening.conf. Il s’intègre bien avec les paquets, rend les diffs lisibles et garde vos changements explicites.

cr0x@server:~$ sudo install -m 0644 -o root -g root /dev/null /etc/ssh/sshd_config.d/50-hardening.conf

High-value settings (safe when staged)

  • Désactiver l’authentification par mot de passe après avoir vérifié les clés : PasswordAuthentication no.
  • Désactiver la connexion root pour SSH interactif : PermitRootLogin no. Si vous avez besoin d’un accès privilégié, utilisez sudo avec des utilisateurs audités.
  • Limiter qui peut se connecter : AllowUsers ou AllowGroups. Cela réduit le périmètre en cas de fuite d’identifiants.
  • Réduire la surface d’attaque : X11Forwarding no sauf si vraiment nécessaire ; beaucoup n’en ont pas besoin. Envisagez aussi des restrictions AllowTcpForwarding par utilisateur.
  • Configurer des timeouts sensés : ClientAliveInterval et ClientAliveCountMax pour nettoyer les sessions mortes.
  • Logger avec intention : LogLevel VERBOSE peut aider l’audit (mais peut ajouter du bruit ; ne le faites pas aveuglément sur des bastions très fréquentés).

Settings that are “secure” but frequently cause lockouts

  • Trop serrer les algorithmes sans inventaire des clients. Si vous retirez le support RSA SHA‑2 sans précaution ou interdisez un KEX requis par des clients anciens, vous obtiendrez des échecs de handshake.
  • Configurer AuthenticationMethods incorrectement. C’est puissant et tranchant. Une faute de frappe peut exiger « deux facteurs » que vous n’avez jamais configurés.
  • Utiliser AllowUsers et oublier les comptes de service (automatisation, sauvegardes, gestion de configuration). Le système ne plantera pas ; votre pipeline, si.

A solid baseline drop-in (adapt it)

Cela est assez conservateur pour la plupart des flottes et assez strict pour avoir un effet. Appliquez-le uniquement après avoir confirmé que l’authentification par clé fonctionne pour tous les comptes requis.

cr0x@server:~$ sudo tee /etc/ssh/sshd_config.d/50-hardening.conf >/dev/null <<'EOF'
# Managed hardening settings (Ubuntu 24.04)

Protocol 2

# Safer defaults: no root, no passwords
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
ChallengeResponseAuthentication no
PubkeyAuthentication yes

# Reduce opportunistic abuse
MaxAuthTries 4
LoginGraceTime 20
MaxStartups 10:30:60

# Hygiene
X11Forwarding no
PermitTunnel no
PermitUserEnvironment no
AllowAgentForwarding no

# Keepalive to clear dead sessions
ClientAliveInterval 300
ClientAliveCountMax 2

# Prefer explicit allowlists (set these to match your org)
# AllowGroups ssh-users

LogLevel VERBOSE
EOF

Comment appliquer sans drame : Gardez une session active ouverte, validez la config (sshd -t), rechargez (pas restart), et testez de nouvelles connexions dans un second terminal.

Stratégie d’authentification : clés, mots de passe, MFA et break-glass

L’authentification SSH n’est pas un simple interrupteur. C’est une stratégie. En production, vous voulez :

  • Une authentification primaire forte et automatisée (clés publiques, idéalement soutenues par un processus de provisioning cohérent).
  • Une défense contre la réutilisation d’identifiants et la force brute (pas de mots de passe, ou au moins pas de mots de passe depuis Internet public).
  • Un accès break-glass contrôlé, audité et testé (parce qu’il sera nécessaire au pire moment).

Keys: do them properly

Les clés Ed25519 sont le choix moderne par défaut pour les utilisateurs interactifs. Elles sont petites, rapides et résistantes à beaucoup d’erreurs historiques. Pour l’automatisation, il se peut que vous ayez encore des clés RSA en circulation ; c’est acceptable si elles utilisent des signatures SHA‑2 et pas des tailles ancestrales.

cr0x@server:~$ ssh-keygen -t ed25519 -a 64 -C "ops@laptop"
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/cr0x/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/cr0x/.ssh/id_ed25519
Your public key has been saved in /home/cr0x/.ssh/id_ed25519.pub

Ce que cela signifie : -a 64 augmente les tours KDF pour la protection de la passphrase. Cela compte si la clé privée fuit un jour.

Décision : Pour les humains : utilisez une passphrase. Pour l’automatisation : envisagez des approches basées sur agent ou des clés restreintes avec commandes forcées et restrictions de source.

Deploy keys with a controlled method

Si vous utilisez ssh-copy-id, faites-le tant que l’authentification par mot de passe est encore activée (temporairement), puis désactivez les mots de passe une fois vérifié.

cr0x@server:~$ ssh-copy-id -i ~/.ssh/id_ed25519.pub ops@server
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/cr0x/.ssh/id_ed25519.pub"
Number of key(s) added: 1
Now try logging into the machine, with:   "ssh 'ops@server'"

Décision : Testez immédiatement avec PasswordAuthentication=no comme montré plus haut. Ne vous fiez pas au « added: 1 » comme preuve d’accès.

MFA: useful, but don’t improvise in production

Le MFA pour SSH peut être fait via PAM (par ex. TOTP) ou via des clés matérielles (FIDO2/U2F avec OpenSSH). Le piège fiabilité : les modifications PAM sont la plomberie globale des connexions. Une petite erreur peut casser non seulement SSH mais aussi les connexions console locales selon la configuration.

Approche pragmatique :

  • Commencez par SSH clé-only + listes d’autorisation réseau + monitoring. C’est déjà une grosse amélioration.
  • Ajoutez le MFA sur des bastions d’abord, pas sur chaque noeud, sauf si vous avez un déploiement et un plan de récupération matures.
  • Si vous utilisez des clés FIDO, assurez-vous que chaque admin a deux appareils et que vous avez un processus pour les clés perdues.

Break-glass: the boring account that saves you

Créez un utilisateur dédié breakglass avec :

  • Authentification par clé uniquement
  • Adresses sources restreintes (VPN ou plages IP bureaux)
  • Droits sudo encadrés par votre politique (souvent sudo complet, mais strictement contrôlé et audité)
  • Pas d’utilisation quotidienne
cr0x@server:~$ sudo adduser --disabled-password --gecos "" breakglass
Adding user `breakglass' ...
Adding new group `breakglass' (1002) ...
Adding new user `breakglass' (1002) with group `breakglass (1002)' ...
Creating home directory `/home/breakglass' ...
Copying files from `/etc/skel' ...
Adding new user `breakglass' to supplemental / extra groups `users' ...
Adding user `breakglass' to group `users' ...

Décision : Gardez ce compte hors des workflows normaux. S’il apparaît dans les logs de connexion réguliers, traitez-le comme une alarme.

Contrôles réseau : UFW, listes d’autorisation, et « n’exposez pas le port 22 à la planète »

Les restrictions réseau sont la modification de durcissement la moins glamour et la plus efficace. Si l’attaquant ne peut pas atteindre le port, votre politique d’authentification devient une seconde ligne de défense au lieu d’être la première.

Bind SSH to a management IP (when you have one)

Si l’hôte a une interface/VLAN de gestion dédiée, liez SSH là. Cela réduit l’exposition même si les règles de pare-feu dérivent.

cr0x@server:~$ sudo tee /etc/ssh/sshd_config.d/10-listen.conf >/dev/null <<'EOF'
ListenAddress 10.20.8.10
EOF

Décision : Ne faites cela que si vous êtes sûr que cette IP est stable et accessible depuis vos réseaux d’administration. Sinon vous inventerez de nouveaux jurons.

UFW allowlist pattern (add before remove)

Si SSH est actuellement ouvert, ne le fermez pas d’un coup. Ajoutez d’abord une règle d’autorisation étroite, testez, puis retirez l’accès large.

cr0x@server:~$ sudo ufw allow from 10.20.0.0/16 to any port 22 proto tcp
Rule added

Ce que cela signifie : Le réseau d’admin est autorisé.

Décision : Confirmez que vous pouvez vous connecter depuis ce réseau. Ce n’est qu’ensuite que vous devez supprimer les règles Anywhere.

Consider a bastion instead of direct node access

Dans de nombreux environnements d’entreprise, le meilleur durcissement SSH est architectural : rendez la plupart des serveurs non routables depuis les réseaux utilisateurs, et exigez un bastion avec un monitoring plus strict. SSH devient un point d’étranglement contrôlé au lieu d’un millier de points d’entrée dispersés.

Blague n°2 : Un bastion, c’est comme le standard de bureau — tout le monde s’en plaint jusqu’au jour où vous l’enlevez.

Résistance aux abus : limites, Fail2ban et réponses pilotées par les logs

Si votre SSH est joignable, il sera scanné. Même en clé-only, les attaquants frapperont les noms d’utilisateur et tenteront des cas limites étranges. Votre travail est de rendre ce bruit peu coûteux à ignorer et coûteux à soutenir.

Use systemd journal + rate limiting as your first line

OpenSSH a des boutons intégrés (MaxStartups, LoginGraceTime, MaxAuthTries). Ils réduisent l’abus de ressources et ralentissent les tentatives de force brute.

Ne les mettez pas à des valeurs absurdement basses sur des bastions ; vous pénaliserez vos propres utilisateurs lors d’une réponse à incident si beaucoup de gens se connectent en même temps.

Fail2ban: still useful, but not a substitute for allowlists

Fail2ban fonctionne en analysant les logs et en ajoutant dynamiquement des règles de pare-feu. C’est utile pour les points d’entrée exposés à Internet, mais c’est réactif et peut être contourné. Traitez-le comme une serpillière, pas comme un barrage.

cr0x@server:~$ sudo apt-get update -y && sudo apt-get install -y fail2ban
Reading package lists... Done
Building dependency tree... Done
The following NEW packages will be installed:
  fail2ban
cr0x@server:~$ sudo systemctl enable --now fail2ban
Created symlink /etc/systemd/system/multi-user.target.wants/fail2ban.service → /usr/lib/systemd/system/fail2ban.service.
cr0x@server:~$ sudo fail2ban-client status sshd
Status for the jail: sshd
|- Filter
|  |- Currently failed: 0
|  |- Total failed: 24
|  `- File list: /var/log/auth.log
`- Actions
   |- Currently banned: 1
   |- Total banned: 3
   `- Banned IP list: 203.0.113.77

Ce que cela signifie : Le jail fonctionne, suit les échecs et bannit les IP abusives.

Décision : Si vous voyez des IP internes bannies, le comportement des allowlists/VPN/NAT peut provoquer une IP de sortie partagée. Ajustez le jail ou, mieux, corrigez le chemin réseau.

Politique cryptographique : ciphers, MACs, KEX et clés hôtes (sans casser les clients)

Le durcissement cryptographique est l’endroit où les bonnes intentions causent de réelles pannes. La bonne approche est incrémentale : inventoriez les capacités clients, choisissez une politique, déployez par étapes et surveillez les échecs de handshake.

First rule: don’t outsmart your fleet

OpenSSH d’Ubuntu 24.04 est déjà moderne. Sauf exigence de conformité, vous n’avez souvent pas besoin de définir explicitement Ciphers/MACs/KexAlgorithms. Les valeurs par défaut évoluent avec les mises à jour ; les pinner peut vous figer dans le temps.

Quand vous devez les définir (conformité, auditeurs, politique cross-distro), faites-le avec une étape d’inventaire et un plan de rollback.

Inventory failures: watch for “no matching…” messages

cr0x@server:~$ ssh -vvv legacy@server
debug1: kex: algorithm: (no match)
Unable to negotiate with 10.20.8.10 port 22: no matching key exchange method found. Their offer: diffie-hellman-group1-sha1

Ce que cela signifie : Le client est ancien et n’offre que des KEX faibles. Votre serveur durci le refuse. C’est probablement correct.

Décision : Mettez à jour le client ou isolez-le derrière un bastion contrôlé qui peut communiquer avec lui. Ne réduisez pas la sécurité de la flotte pour un seul fossile.

Host keys: keep them sane, keep them stable

Les clés hôtes sont l’identité du serveur. Les faire tourner sans plan déclenche « REMOTE HOST IDENTIFICATION HAS CHANGED! », que les utilisateurs apprendront à ignorer. C’est l’inverse de ce que vous voulez.

cr0x@server:~$ sudo ssh-keygen -l -f /etc/ssh/ssh_host_ed25519_key.pub
256 SHA256:8t7mZlQZ9l8m0n3H9Jx7qWzYkqvHqQx0mJv4pYkq8mE root@server (ED25519)

Décision : Assurez-vous d’avoir des clés hôtes modernes (Ed25519, ECDSA, RSA SHA‑2). Si vous prévoyez une rotation, coordonnez les mises à jour de known_hosts via la gestion de configuration, pas par email.

Garde-fous opérationnels : contrôle des changements, tests et rollback

Le « durcissement » n’est pas un acte héroïque. C’est un déploiement contrôlé.

Keep an active session and open a second one before reload

Lorsque vous rechargez sshd, les sessions existantes restent typiquement. C’est votre ligne de vie. Ouvrez une seconde session avant les changements pour tester de nouvelles connexions tout en conservant un canal connu bon ouvert.

Prefer reload over restart

systemctl reload ssh demande à sshd de relire la configuration sans couper les connexions existantes. Restart est plus perturbateur et plus susceptible de vous laisser sur la touche si un échec de démarrage se produit.

Know your out-of-band access before you need it

Console cloud, IPMI, console hyperviseur ou accès physique. Testez-le trimestriellement. Oui, tous les trois mois. La première fois que vous l’utilisez ne devrait pas être pendant une fenêtre d’incident pendant que Slack déborde d’opinions.

Back up config files with a timestamp

cr0x@server:~$ sudo cp -a /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%F_%H%M%S)

Décision : Si quelque chose part en sucette, vous voulez un fichier connu bon, pas un souvenir de ce que vous avez changé.

Playbook de diagnostic rapide

Quand SSH « casse », c’est généralement une des quatre catégories : démon arrêté, réseau bloqué, authentification refusée, ou échec de négociation crypto. Diagnosez dans cet ordre. Rapidement. Sans tergiverser.

1) Is sshd up and listening?

  • Sur la console serveur (ou via une session existante) : vérifiez le statut du service et les sockets d’écoute.
cr0x@server:~$ systemctl is-active ssh; ss -tulpn | grep sshd
active
tcp   LISTEN 0      128          10.20.8.10:22        0.0.0.0:*    users:(("sshd",pid=1247,fd=3))

Si ce n’est pas actif/à l’écoute : syntaxe de config, permissions, ou problèmes de paquet. Passez à sshd -t et consultez les journaux du journal.

2) Is the network path open?

  • Côté client : obtenez-vous une connexion TCP ou un timeout ?
  • Côté serveur : les règles de pare-feu permettent-elles votre IP source ?
cr0x@server:~$ sudo ufw status verbose
Status: active
Default: deny (incoming), allow (outgoing), disabled (routed)

Les timeouts signifient généralement réseau/pare-feu. « Connection refused » immédiat signifie généralement que sshd n’écoute pas (ou port différent).

3) Is it auth policy?

  • Côté client : utilisez SSH verbeux.
  • Côté serveur : vérifiez les logs ssh pour « Authentication refused » ou « user not allowed ».
cr0x@server:~$ ssh -vvv ops@server
debug1: Authentications that can continue: publickey
debug1: Offering public key: /home/cr0x/.ssh/id_ed25519 ED25519 SHA256:2d3v...
debug1: Server accepts key: /home/cr0x/.ssh/id_ed25519
debug1: Authentication succeeded (publickey).

Si vous voyez « Permission denied (publickey) » : vérifiez le déploiement de la clé, les permissions des fichiers, AllowUsers/AllowGroups, et tout bloc Match.

4) Is it crypto negotiation?

Cherchez les messages « no matching » : KEX, algorithme de clé hôte, cipher, ou MAC. C’est souvent un problème d’âge du client ou une politique serveur trop figée.

Erreurs courantes : symptôme → cause racine → correction

1) Symptom: Existing sessions stay up, but new logins fail immediately

Cause racine : Vous avez rechargé sshd avec une politique plus stricte (PasswordAuthentication no, AllowGroups, ou AuthenticationMethods) et votre utilisateur de test ne correspond pas.

Correction : Dans votre session existante, exécutez sshd -T, confirmez les paramètres effectifs, et ajustez les listes d’autorisation ou restaurez temporairement l’authentification par mot de passe pendant que vous réparez l’accès par clé.

2) Symptom: “Connection refused”

Cause racine : sshd n’écoute pas sur cette interface/ce port (mauvais ListenAddress, mauvais port, service arrêté).

Correction : ss -tulpn pour confirmer les écouteurs ; journalctl -u ssh pour les erreurs de démarrage ; corrigez la config, puis reload ou restart si nécessaire.

3) Symptom: “Connection timed out”

Cause racine : Pare-feu/groupe de sécurité/ACL réseau bloquant, ou problème de routage/VPN.

Correction : Vérifiez les règles UFW et les règles en amont. Ajoutez une autorisation temporaire et étroite depuis votre IP actuelle, testez, puis nettoyez.

4) Symptom: “Permission denied (publickey)” but your key is present

Cause racine : sshd ignore authorized_keys à cause de permissions non sûres ou mauvaise propriété ; ou l’utilisateur n’est pas autorisé par AllowUsers/AllowGroups.

Correction : Corrigez les permissions à 700 sur .ssh et 600 sur authorized_keys. Vérifiez la propriété. Confirmez les règles allow.

5) Symptom: “REMOTE HOST IDENTIFICATION HAS CHANGED!” after a maintenance event

Cause racine : Rotation inattendue des clés hôtes (rebuild, restore, ou changement d’image) sans propagation des mises à jour known_hosts.

Correction : Validez le nouvel empreinte de clé hôte hors bande, puis mettez à jour known_hosts centralement. N’apprenez pas aux utilisateurs à ignorer les avertissements.

6) Symptom: Some automation breaks, humans are fine

Cause racine : Vous avez désactivé l’authentification par mot de passe et l’automatisation l’utilisait encore ; ou la bibliothèque cliente d’automatisation ne peut pas négocier les nouveaux algorithmes.

Correction : Identifiez les comptes en échec dans les logs, migrez l’automatisation vers des clés ou des certificats SSH, et testez avec la même version cliente utilisée en CI/CD.

Checklists / step-by-step plan

Phase 0: Pre-flight (don’t skip this)

  1. Confirmez que l’accès console/hors-bande existe et fonctionne (console série cloud, IPMI, console hyperviseur).
  2. Ouvrez deux sessions SSH depuis des terminaux différents.
  3. Sauvegardez la config SSH et notez les paramètres effectifs actuels :
    • sudo cp -a /etc/ssh/sshd_config ...
    • sudo sshd -T > /root/sshd-effective.before
  4. Inventoriez qui se connecte et comment (entrées du journal, logs du bastion, comptes d’automatisation).

Phase 1: Network-first tightening

  1. Implémentez des listes d’autorisation dans UFW (ou groupes de sécurité cloud) pour limiter les sources SSH aux réseaux admin/VPN.
  2. Testez la connectivité depuis chaque réseau autorisé.
  3. Ce n’est qu’ensuite que vous supprimez les règles larges.

Phase 2: Key auth everywhere

  1. Assurez-vous que chaque compte humain et d’automatisation requis a un login clé-fonctionnel.
  2. Vérifiez avec PasswordAuthentication=no côté client.
  3. Corrigez proactivement les permissions et la propriété.

Phase 3: Enforce no-password, no-root

  1. Ajoutez un drop-in géré avec PasswordAuthentication no et PermitRootLogin no.
  2. Exécutez sudo sshd -t.
  3. Rechargez sshd, pas restart.
  4. Testez un nouveau login en tant qu’utilisateur admin normal et en tant que break-glass.

Phase 4: Reduce SSH features you don’t need

  1. Désactivez le forwarding X11 sauf si nécessaire.
  2. Désactivez par défaut l’agent forwarding. Si votre workflow en a besoin, activez-le par utilisateur avec des blocs Match.
  3. Restreignez le port forwarding si SSH est utilisé seulement pour un shell.

Phase 5: Abuse resistance and monitoring

  1. Définissez MaxAuthTries, LoginGraceTime, MaxStartups de façon sensée.
  2. Déployez Fail2ban là où c’est approprié (endpoints publics), mais ne comptez pas dessus comme contrôle primaire.
  3. Revoyez les logs chaque semaine jusqu’à stabilisation, puis chaque mois.

Trois mini-histoires d’entreprise du pays des changements SSH regrettables

Mini-story 1: The incident caused by a wrong assumption

L’entreprise avait un parc mixte : un peu d’Ubuntu, du RHEL, et quelques appliances que personne n’osait admettre encore en service. Un ingénieur a décidé de standardiser les politiques SSH pendant un « security sprint ». Objectif raisonnable. Ils ont ajouté AllowGroups ssh-admins sur toute la flotte, convaincus que « tous les admins sont dans ce groupe ».

Sur le papier, c’était vrai. En pratique, il y avait trois sources d’identité différentes : utilisateurs locaux sur des hôtes anciens, LDAP sur les plus récents, et une intégration IAM sur les bastions. Sur plusieurs serveurs, le groupe existait — mais les comptes admin n’en étaient pas membres parce que ces comptes avaient été créés localement lors d’incidents passés. Personne n’avait nettoyé tout ça. L’hypothèse d’une identité centralisée partout était fausse.

Le changement a été déployé. Les sessions SSH existantes sont restées, ce qui a donné à tous une confiance trompeuse. Les nouvelles sessions ont échoué. L’équipe d’astreinte a commencé à faire tourner des terminaux comme des contrôleurs aériens parce qu’ils ne voulaient pas perdre leurs dernières sessions restantes. Un patch kernel routine était à mi-chemin et n’a pas pu rétablir les connexions pour finir.

La correction a été ennuyeuse et légèrement humiliante : revert du AllowGroups, audit propre des appartenances aux groupes, puis réintroduction des listes d’autorisation en étapes via un bloc Match Address pour le chemin break-glass en premier. La leçon durable n’était pas « ne jamais utiliser AllowGroups ». C’était « ne jamais supposer que l’identité est uniforme à moins de l’avoir prouvé ».

Mini-story 2: The optimization that backfired

Une autre organisation gérait un bastion très utilisé. Ils avaient des milliers de connexions SSH courtes : humains, automatisation, scripts faisant « une commande puis exit ». Quelqu’un a remarqué des pics CPU sous charge et a décidé d’« optimiser » en réduisant les timeouts et les connexions non authentifiées concurrentes.

Ils ont mis LoginGraceTime trop bas et MaxStartups trop strict, pensant ne pénaliser que les bots. Pendant un incident routine, un flapping VPN a causé la reconnexion simultanée de nombreux utilisateurs. Le bastion a commencé à refuser de nouvelles connexions précisément au moment où il était le plus nécessaire. L’équipe sécurité a adoré les nouveaux réglages ; le responsable de l’incident, moins.

Pire, le mode de défaillance ressemblait à une instabilité réseau. Les utilisateurs ont vu des déconnexions et des timeouts intermittents. Les gens ont blâmé le VPN, puis le DNS, puis le réseau cloud. La cause racine était l’admission control auto-infligé par sshd sous des conditions de reconnexion en rafale.

Ils sont revenus à une courbe MaxStartups plus tolérante et ont légèrement augmenté le LoginGraceTime. Les pics CPU sont restés gérables et le bastion est redevenu prévisible. La morale : optimiser SSH comme un benchmark, c’est découvrir que votre charge inclut des humains se comportant comme un troupeau en furie.

Mini-story 3: The boring but correct practice that saved the day

Une société financière avait une règle stricte : chaque changement de politique SSH requérait (1) un hôte canari, (2) un test d’accès hors-bande, et (3) une vérification scriptée du login clé-only avant de désactiver les mots de passe. Ça semblait bureaucratique. Ça fonctionnait aussi.

Ils prévoyaient de désactiver l’authentification par mot de passe sur toute la flotte. Avant l’application, leur pipeline a lancé un test qui a tenté un login avec PasswordAuthentication=no pour chaque compte privilégié important. Un canari a échoué : un job d’automatisation legacy utilisait encore l’authentification par mot de passe pour accéder à une machine de reporting. Personne ne le savait parce que c’était « installé et oublié » depuis des années.

Parce que le test a été exécuté avant l’application, rien n’a cassé. Ils ont corrigé le job pour utiliser une clé dédiée avec permissions de commande restreintes, relancé le test, puis déployé la config à l’échelle.

Il n’y a pas eu de drame, pas d’accès console d’urgence, et pas de rollback nocturne. L’amélioration de sécurité s’est installée discrètement. Voilà à quoi ressemble la bonne pratique en production : pas héroïque, juste répétable.

FAQ

1) Should I change the SSH port from 22?

Si vous êtes exposé à Internet, changer de port réduit le bruit des scans automatiques mais n’arrêtera pas les attaquants ciblés. Faites-le seulement si cela ne complique pas vos outils. Préférez les listes d’autorisation réseau et l’authentification par clé.

2) Is disabling password authentication always safe?

C’est sûr lorsque vous avez vérifié l’accès par clé pour chaque utilisateur et chaque chemin d’automatisation requis, et que vous avez un plan break-glass. C’est risqué quand vous « pensez » que les clés sont déployées mais ne les avez pas testées avec le fallback mot de passe désactivé.

3) What’s the safest way to apply changes: reload or restart?

Rechargez d’abord. systemctl reload ssh garde les sessions existantes. Restart est acceptable quand nécessaire, mais augmente le risque de verrouillage complet si la config est cassée.

4) Should I set explicit Ciphers/MACs/KexAlgorithms?

Seulement si vous devez le faire pour conformité ou cohérence cross-distro. Les valeurs par défaut sont généralement bonnes et s’améliorent avec les mises à jour. Pinner les algorithmes peut créer une panne future quand les clients divergent.

5) How do I prevent root access without losing admin capability?

Désactivez la connexion root sur SSH (PermitRootLogin no) et utilisez des comptes nommés avec sudo. Vous obtenez des traces d’audit et pouvez révoquer l’accès proprement.

6) What about SSH agent forwarding?

Désactivez-le par défaut (AllowAgentForwarding no). Si certains workflows en ont besoin, activez-le dans un bloc ciblé Match User et gardez-le désactivé sur les bastions sauf si vous faites vraiment confiance au saut.

7) Do I need Fail2ban if I already have UFW allowlists?

Si SSH est strictement allowlisté à des réseaux privés, l’intérêt de Fail2ban diminue. Si SSH est joignable depuis Internet (même temporairement), Fail2ban est utile comme couche supplémentaire, pas comme défense primaire.

8) What’s the single best “won’t lock you out” trick?

Démarrez un sshd canari temporaire sur un autre port avec les réglages stricts envisagés, testez-le de bout en bout, puis appliquez les réglages au service principal.

9) How do I know if I broke crypto compatibility?

Un ssh -vvv côté client montrera des échecs de négociation comme « no matching key exchange method ». Les logs serveur peuvent aussi montrer des algorithmes rejetés. La solution est généralement de mettre à jour le client, pas d’affaiblir le serveur.

10) Can I enforce different SSH policies for different users?

Oui. Utilisez Match User, Match Group ou Match Address pour appliquer des réglages plus stricts ou plus permissifs selon le périmètre. C’est comme ça que vous gardez le break-glass contrôlé tout en appliquant des defaults forts pour les autres.

Conclusion : que faire ensuite

Le durcissement SSH sur Ubuntu 24.04 n’a pas besoin d’être théâtral. Faites-le comme un opérateur : réduisez d’abord l’exposition, prouvez l’accès par clé, puis appliquez une authentification plus stricte. Évitez de pinner les algorithmes sans raison. Préférez les reloads aux restarts. Gardez un chemin break-glass que vous testez réellement, pas seulement dont vous parlez.

Prochaines étapes pratiques :

  1. Exécutez les tâches de base : confirmez la configuration effective, les écouteurs, la portée du pare-feu et les modes de connexion réels.
  2. Ajoutez/vérifiez un utilisateur break-glass avec authentification par clé et réseaux sources restreints.
  3. Déployez un fichier drop-in de durcissement en canari → petit lot → flotte complète, avec sshd -t et une porte de test de connexion scriptée.
  4. Après l’application, passez une semaine à surveiller les logs d’auth tous les jours. Le système vous dira ce que vous avez cassé — si vous écoutez.
← Précédent
Debian 13 : NFS plus lent que prévu — prouvez que c’est sync/rsize/wsize et corrigez-le (cas n°23)
Suivant →
Contrôle d’accès VPN bureau : autoriser uniquement ce qui est nécessaire (pas de LAN-à-LAN complet)

Laisser un commentaire