Introduction : SSH, le maillon critique de votre infrastructure
Soyons honnêtes : SSH, c'est un peu le gardien silencieux de toute infrastructure Linux. Chaque serveur en production, chaque pipeline CI/CD, chaque transfert de fichier sécurisé repose, d'une manière ou d'une autre, sur OpenSSH. Et cette omniprésence en fait une cible de choix pour les attaquants — tentatives de brute force, exploitation de vulnérabilités, vol de clés privées, attaques man-in-the-middle. Selon CrowdSec, les attaques SSH par force brute représentent plus de 60 % des tentatives d'intrusion détectées sur les serveurs Linux exposés à Internet. Ça fait réfléchir.
L'année 2025 a marqué un vrai tournant avec la sortie d'OpenSSH 10.0 en avril, puis d'OpenSSH 10.1 en octobre. On parle de changements fondamentaux : cryptographie post-quantique activée par défaut, suppression définitive de DSA, séparation du code d'authentification dans un binaire dédié, et des valeurs par défaut nettement plus strictes. En parallèle, les clés matérielles FIDO2 et les certificats SSH à durée de vie courte se sont généralisés.
Ce guide vous accompagne dans la mise en place d'une stratégie de durcissement SSH complète, adaptée aux menaces de 2026. On va couvrir la config avancée d'OpenSSH, la migration vers la crypto post-quantique, l'authentification FIDO2, les certificats SSH, l'audit de configuration, et les outils de défense active. Chaque section contient des exemples concrets et des commandes prêtes à copier-coller.
OpenSSH 10 : les changements majeurs à connaître
La cryptographie post-quantique par défaut
C'est sans doute le changement le plus marquant d'OpenSSH 10.0 : l'adoption de l'algorithme hybride mlkem768x25519-sha256 comme méthode d'échange de clés par défaut. Cet algorithme combine ML-KEM (Module-Lattice-Based Key Encapsulation Mechanism), standardisé par le NIST sous FIPS 203, avec la courbe elliptique X25519. L'idée est simple mais élégante — même si l'un des deux algorithmes tombe, l'autre maintient la confidentialité des échanges.
Pourquoi c'est important ? Parce que les ordinateurs quantiques capables de casser RSA et ECDH sont en développement actif. Et le concept de « récolter maintenant, déchiffrer plus tard » (harvest now, decrypt later) signifie que des données chiffrées aujourd'hui pourraient être compromises dans quelques années seulement. Le NIST fixe 2035 comme échéance pour la migration complète, mais franchement, les experts recommandent de ne pas attendre.
OpenSSH 10.1 va encore plus loin en affichant un avertissement lorsqu'un échange de clés non post-quantique est négocié, via la directive WarnWeakCrypto. Voici la hiérarchie actuelle des algorithmes :
# Ordre de préférence par défaut dans OpenSSH 10.x
# 1. mlkem768x25519-sha256 (hybride post-quantique, DÉFAUT)
# 2. sntrup761x25519-sha512 (hybride post-quantique, alternatif)
# 3. curve25519-sha256 (classique, toujours sûr)
# 4. ecdh-sha2-nistp256 (classique NIST)
# 5. ecdh-sha2-nistp384 (classique NIST)
# 6. ecdh-sha2-nistp521 (classique NIST)
# Note : diffie-hellman-group* DÉSACTIVÉ par défaut dans sshd
Suppression définitive de DSA
Bon, celui-là, on l'attendait depuis longtemps. OpenSSH 10.0 achève enfin la dépréciation de l'algorithme DSA, entamée en 2015. Le support compile-time a été totalement retiré. Si vous avez encore des clés DSA qui traînent quelque part dans votre infra (et croyez-moi, certaines organisations en ont), c'est le moment de les remplacer immédiatement par des clés Ed25519 ou ECDSA.
# Vérifier la présence de clés DSA sur vos serveurs
find /etc/ssh/ -name "*dsa*" -type f 2>/dev/null
find /home -name "id_dsa*" -type f 2>/dev/null
# Générer une nouvelle clé Ed25519 pour remplacer DSA
ssh-keygen -t ed25519 -C "[email protected]" -f ~/.ssh/id_ed25519
# Sur les serveurs, remplacer la clé hôte DSA
sudo ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N ""
sudo ssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key -N ""
Séparation architecturale : le nouveau binaire sshd-auth
OpenSSH 10 introduit une amélioration architecturale assez élégante : le code d'authentification pré-connexion a été déplacé du binaire sshd-session vers un nouveau binaire dédié sshd-auth. Concrètement, la phase d'authentification (celle qui est la plus exposée, puisqu'elle s'exécute avant toute vérification d'identité) tourne maintenant dans un espace d'adressage complètement séparé.
Les bénéfices sont multiples :
- Réduction de la surface d'attaque : un exploit dans le code pré-authentification ne donne plus accès au code de session
- Économie mémoire : une fois l'authentification terminée, le code est déchargé
- Re-linkage aléatoire : comme les autres composants (
sshd,ssh-session,ssh-agent), le binairesshd-authest re-linké aléatoirement au démarrage, ce qui rend les exploits basés sur l'adressage mémoire bien plus compliqués
Déplacement des sockets d'agent
Petit changement, mais gros impact : OpenSSH 10.1 déplace les sockets d'écoute de ssh-agent et sshd depuis /tmp vers ~/.ssh/agent/. Résultat, les processus qui ont accès à /tmp mais pas à votre répertoire personnel ne peuvent plus détourner vos clés chargées dans l'agent. Simple, efficace.
Configuration avancée du serveur SSH
Configuration de base durcie
Allez, passons aux choses concrètes. Voici une configuration sshd_config complète et durcie, adaptée à OpenSSH 10.x sur un serveur de production :
# /etc/ssh/sshd_config - Configuration durcie pour OpenSSH 10.x
# Dernière mise à jour : février 2026
# === Paramètres réseau ===
Port 22
AddressFamily inet
ListenAddress 0.0.0.0
# === Authentification ===
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
AuthenticationMethods publickey
# Nombre maximum de tentatives et sessions
MaxAuthTries 3
MaxSessions 5
MaxStartups 10:30:60
# === Algorithmes cryptographiques ===
# Échange de clés : post-quantique en priorité
KexAlgorithms mlkem768x25519-sha256,sntrup761x25519-sha512,curve25519-sha256
# Chiffrements : AES-GCM et ChaCha20 uniquement
Ciphers [email protected],[email protected],[email protected]
# MACs : uniquement ETM (Encrypt-then-MAC)
MACs [email protected],[email protected]
# Clés hôte
HostKey /etc/ssh/ssh_host_ed25519_key
HostKey /etc/ssh/ssh_host_rsa_key
HostKeyAlgorithms ssh-ed25519,rsa-sha2-512,rsa-sha2-256
# === Durcissement divers ===
X11Forwarding no
AllowTcpForwarding no
AllowAgentForwarding no
PermitTunnel no
GatewayPorts no
PermitUserEnvironment no
DisableForwarding yes
# Bannière légale
Banner /etc/ssh/banner.txt
# Délais et inactivité
LoginGraceTime 30
ClientAliveInterval 300
ClientAliveCountMax 2
# Journalisation
LogLevel VERBOSE
SyslogFacility AUTH
# Restriction par groupe (créer le groupe ssh-users)
AllowGroups ssh-users
# Chroot pour les utilisateurs SFTP
Subsystem sftp internal-sftp
Match Group sftp-only
ForceCommand internal-sftp
ChrootDirectory /data/sftp/%u
AllowTcpForwarding no
X11Forwarding no
Explication des choix cryptographiques
Quelques précisions sur les choix faits dans cette configuration (parce que copier-coller sans comprendre, c'est jamais une bonne idée) :
- KexAlgorithms : les algorithmes post-quantiques sont en tête.
mlkem768x25519-sha256est le nouveau défaut d'OpenSSH 10, tandis quesntrup761x25519-sha512(dispo depuis OpenSSH 9.0) offre une alternative.curve25519-sha256est conservé en repli pour les clients plus anciens. - Ciphers :
chacha20-poly1305reste prioritaire — excellente performance sans accélération matérielle AES-NI et résistance aux attaques par canaux auxiliaires. Les modes AES-GCM complètent le tableau sur les processeurs modernes. - MACs : seuls les modes ETM (Encrypt-then-MAC) sont conservés. Les modes MAC-then-Encrypt classiques sont vulnérables à certaines attaques théoriques. Notez qu'avec les chiffrements AEAD (GCM, ChaCha20-Poly1305), la ligne MACs est tout simplement ignorée puisque l'authentification est intégrée au chiffrement.
- HostKeyAlgorithms : Ed25519 en priorité (courbes de Bernstein, performant, clés compactes), RSA-SHA2 en repli pour la compatibilité.
Configuration côté client
Le durcissement ne doit pas se limiter au serveur — ça, c'est un point qu'on oublie trop souvent. Voici une configuration ~/.ssh/config sécurisée :
# ~/.ssh/config - Configuration client durcie
Host *
# Algorithmes post-quantiques en priorité
KexAlgorithms mlkem768x25519-sha256,sntrup761x25519-sha512,curve25519-sha256
Ciphers [email protected],[email protected],[email protected]
MACs [email protected],[email protected]
HostKeyAlgorithms ssh-ed25519,rsa-sha2-512,rsa-sha2-256
# Vérification stricte des clés hôte
StrictHostKeyChecking ask
UpdateHostKeys yes
VisualHostKey yes
# Multiplexage des connexions
ControlMaster auto
ControlPath ~/.ssh/sockets/%r@%h-%p
ControlPersist 600
# Protection des clés
AddKeysToAgent yes
IdentitiesOnly yes
# Délai de connexion
ConnectTimeout 15
ServerAliveInterval 60
ServerAliveCountMax 3
# Exemple : serveur de production
Host prod-web-*
User deployer
IdentityFile ~/.ssh/id_ed25519_prod
ProxyJump bastion.mondomaine.fr
ForwardAgent no
Authentification par clés matérielles FIDO2
Pourquoi passer aux clés FIDO2 ?
Les clés SSH traditionnelles (Ed25519, RSA) sont stockées sous forme de fichiers sur le disque. Même protégées par une passphrase, elles restent vulnérables au vol si la machine est compromise : un keylogger capture la passphrase, un malware copie le fichier de clé, et c'est fini. Les clés FIDO2 (types ed25519-sk et ecdsa-sk) résolvent ce problème fondamental : la clé privée ne quitte jamais le dispositif matériel.
C'est un vrai changement de paradigme. Avec FIDO2, chaque authentification SSH nécessite :
- Présence physique : il faut toucher la clé matérielle (YubiKey, SoloKey, Nitrokey…)
- Vérification utilisateur (optionnelle mais recommandée) : saisie d'un code PIN sur le dispositif
- Résistance au phishing : l'authentification est liée cryptographiquement au serveur cible
Génération de clés FIDO2 pour SSH
OpenSSH 8.2+ supporte les clés FIDO2. Voici comment les configurer :
# Prérequis : installer la bibliothèque libfido2
# Debian/Ubuntu
sudo apt install libfido2-dev libfido2-1 fido2-tools
# RHEL/Fedora
sudo dnf install libfido2-devel libfido2 fido2-tools
# Générer une clé Ed25519-SK (FIDO2)
# L'option -O resident stocke la clé sur le dispositif
# L'option -O verify-required exige le PIN à chaque utilisation
ssh-keygen -t ed25519-sk -O resident -O verify-required \
-O application=ssh:production -C "[email protected] - YubiKey"
# Générer une clé ECDSA-SK (compatibilité plus large)
ssh-keygen -t ecdsa-sk -O resident -O verify-required \
-C "[email protected] - YubiKey"
# Lister les clés résidentes stockées sur le dispositif
ssh-keygen -K
Déploiement des clés FIDO2 sur les serveurs
# Copier la clé publique sur le serveur distant
ssh-copy-id -i ~/.ssh/id_ed25519_sk.pub [email protected]
# Ou manuellement
cat ~/.ssh/id_ed25519_sk.pub | ssh utilisateur@serveur \
"mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
# Configurer sshd pour accepter les clés SK
# Dans /etc/ssh/sshd_config
PubkeyAcceptedAlgorithms ssh-ed25519,[email protected],[email protected],rsa-sha2-512,rsa-sha2-256
Stratégie de clés de secours
Un point crucial qu'il ne faut surtout pas négliger : la perte d'une clé matérielle FIDO2 pourrait vous verrouiller hors de vos serveurs. J'ai vu ça arriver dans une boîte où j'intervenais — pas drôle du tout. Voici comment mettre en place une stratégie de récupération solide :
# 1. Enregistrer DEUX clés matérielles pour chaque serveur
# (une principale, une de secours dans un coffre-fort)
ssh-keygen -t ed25519-sk -O resident -O verify-required \
-C "admin - YubiKey principale"
ssh-keygen -t ed25519-sk -O resident -O verify-required \
-C "admin - YubiKey secours"
# 2. Ajouter les DEUX clés publiques dans authorized_keys
cat id_ed25519_sk_principale.pub id_ed25519_sk_secours.pub >> ~/.ssh/authorized_keys
# 3. Conserver aussi un accès d'urgence via une clé Ed25519 classique
# stockée chiffrée dans un gestionnaire de mots de passe
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_urgence -C "clé urgence"
# Stocker cette clé de manière sécurisée et hors ligne
Certificats SSH : au-delà des clés autorisées
Le problème des fichiers authorized_keys
La gestion traditionnelle par fichiers authorized_keys, on connaît tous. Et on connaît aussi ses limites :
- Prolifération des clés : selon Venafi, 90 % des organisations n'ont pas d'inventaire complet de leurs clés SSH, et 61 % ne contrôlent pas qui peut les gérer (c'est assez effrayant quand on y pense)
- Pas d'expiration : une clé ajoutée dans
authorized_keysreste valide indéfiniment, sauf suppression manuelle - Pas de révocation efficace : retirer l'accès à un employé qui quitte l'entreprise nécessite de parcourir chaque serveur
- Pas d'identité vérifiable : la clé publique ne porte aucune information sur son propriétaire
Comment fonctionnent les certificats SSH
Les certificats SSH résolvent ces problèmes en introduisant une autorité de certification (CA) qui signe les clés publiques. Un certificat SSH contient :
- L'identité de l'utilisateur (principal)
- Une date d'expiration (TTL)
- Des restrictions (commandes autorisées, adresses IP sources, options)
- La signature de la CA
En gros, c'est comme passer d'un système de clés physiques qu'on distribue à tout le monde à un système de badges avec date d'expiration. Bien plus gérable à l'échelle.
Mise en place d'une CA SSH
# === Création de la CA ===
# Clé CA pour les certificats utilisateurs
ssh-keygen -t ed25519 -f /etc/ssh/ca/user_ca -C "CA Utilisateurs SSH"
# Clé CA pour les certificats hôtes (séparation recommandée)
ssh-keygen -t ed25519 -f /etc/ssh/ca/host_ca -C "CA Hôtes SSH"
# Protéger les clés CA
chmod 600 /etc/ssh/ca/user_ca /etc/ssh/ca/host_ca
chown root:root /etc/ssh/ca/user_ca /etc/ssh/ca/host_ca
# === Signer un certificat utilisateur ===
# Certificat valide 8 heures, pour l'utilisateur "deployer"
# avec accès restreint aux serveurs web
ssh-keygen -s /etc/ssh/ca/user_ca \
-I "[email protected]" \
-n deployer \
-V +8h \
-O source-address=10.0.0.0/8 \
deployer_id_ed25519.pub
# Vérifier le certificat généré
ssh-keygen -L -f deployer_id_ed25519-cert.pub
# === Signer un certificat hôte ===
ssh-keygen -s /etc/ssh/ca/host_ca \
-I "web-prod-01.mondomaine.fr" \
-h \
-n web-prod-01.mondomaine.fr,web-prod-01,10.0.1.10 \
-V +52w \
/etc/ssh/ssh_host_ed25519_key.pub
Configuration du serveur pour les certificats
# /etc/ssh/sshd_config - Ajouts pour les certificats
# Faire confiance à la CA utilisateur
TrustedUserCAKeys /etc/ssh/ca/user_ca.pub
# Certificat hôte (élimine les avertissements TOFU)
HostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub
# Optionnel : mapper les principaux aux utilisateurs Unix
AuthorizedPrincipalsFile /etc/ssh/auth_principals/%u
# Fichier de révocation
RevokedKeys /etc/ssh/revoked_keys
# /etc/ssh/auth_principals/deployer
deployer
webadmin
ci-deploy
# Configuration client pour faire confiance aux hôtes certifiés
# ~/.ssh/known_hosts
@cert-authority *.mondomaine.fr ssh-ed25519 AAAA...clé_publique_host_ca...
Automatisation avec un service de signature
Pour une infrastructure de taille moyenne ou grande, la signature manuelle des certificats ne passe tout simplement pas à l'échelle. Des outils comme step-ca (de Smallstep) ou Vault SSH (de HashiCorp) automatisent tout ça très bien :
# Exemple avec step-ca (Smallstep)
# Installation
wget https://dl.smallstep.com/gh-release/certificates/docs-ca-install/v0.27.5/step-ca_0.27.5_amd64.deb
sudo dpkg -i step-ca_0.27.5_amd64.deb
# Initialiser la CA
step ca init --ssh
# Démarrer le service
step-ca $(step path)/config/ca.json &
# Demander un certificat SSH (authentification OIDC)
step ssh certificate [email protected] ~/.ssh/id_ed25519 \
--provisioner "Google" \
--principal deployer \
--principal webadmin
# Le certificat expire automatiquement après la durée configurée
# Pas besoin de gérer authorized_keys !
Auditer votre configuration SSH avec ssh-audit
Installation et utilisation de ssh-audit
ssh-audit est clairement l'outil de référence pour évaluer la sécurité de votre config SSH. Il analyse les algorithmes proposés par le serveur, identifie les vulnérabilités connues et attribue un score global. C'est un peu le Lighthouse de la sécu SSH, si vous voulez.
# Installation via pip
pip3 install ssh-audit
# Installation via le gestionnaire de paquets
# Debian/Ubuntu
sudo apt install ssh-audit
# Audit d'un serveur distant
ssh-audit monserveur.mondomaine.fr
# Audit sur un port non standard
ssh-audit -p 2222 monserveur.mondomaine.fr
# Audit au format JSON (pour traitement automatisé)
ssh-audit -j monserveur.mondomaine.fr > audit_results.json
# Audit en mode politique (vérification de conformité)
ssh-audit -P hardened monserveur.mondomaine.fr
Interpréter les résultats
ssh-audit classe les algorithmes en plusieurs catégories :
- Vert : algorithme sûr, recommandé
- Orange : acceptable mais à surveiller
- Rouge : faible ou vulnérable, à désactiver immédiatement
Un serveur correctement configuré avec notre config ci-dessus devrait obtenir un score A+. Voici à quoi ça ressemble :
# Résultat attendu pour une configuration durcie
(gen) banner: SSH-2.0-OpenSSH_10.1
(gen) software: OpenSSH 10.1
(gen) compatibility: OpenSSH 8.5+
(gen) compression: enabled ([email protected])
(kex) mlkem768x25519-sha256 -- [info] available since OpenSSH 9.9
(kex) sntrup761x25519-sha512 -- [info] available since OpenSSH 8.5
(kex) curve25519-sha256 -- [info] available since OpenSSH 7.4
(key) ssh-ed25519 -- [info] available since OpenSSH 6.5
(key) rsa-sha2-512 -- [info] available since OpenSSH 7.2
(key) rsa-sha2-256 -- [info] available since OpenSSH 7.2
(enc) [email protected] -- [info] available since OpenSSH 6.5
(enc) [email protected] -- [info] available since OpenSSH 6.2
(enc) [email protected] -- [info] available since OpenSSH 6.2
(mac) [email protected] -- [info] available since OpenSSH 6.2
(mac) [email protected] -- [info] available since OpenSSH 6.2
# Overall Score: A+ (100/100)
Automatiser l'audit dans votre infrastructure
Sur une flotte de serveurs, lancer ssh-audit manuellement un par un n'est pas viable. Voici un script qui automatise ça et envoie une alerte en cas de non-conformité :
#!/bin/bash
# Script d'audit SSH automatisé pour une flotte de serveurs
# audit_ssh_fleet.sh
SERVERS_FILE="/etc/ssh-audit/servers.list"
REPORT_DIR="/var/log/ssh-audit"
DATE=$(date +%Y-%m-%d)
ALERT_EMAIL="[email protected]"
mkdir -p "${REPORT_DIR}"
echo "=== Audit SSH de la flotte - ${DATE} ===" | tee "${REPORT_DIR}/rapport_${DATE}.txt"
FAILURES=0
while IFS= read -r server; do
[[ "$server" =~ ^#.*$ || -z "$server" ]] && continue
echo "--- Audit de ${server} ---" | tee -a "${REPORT_DIR}/rapport_${DATE}.txt"
# Exécuter ssh-audit en mode politique
RESULT=$(ssh-audit -P hardened "${server}" 2>&1)
EXIT_CODE=$?
echo "$RESULT" | tee -a "${REPORT_DIR}/rapport_${DATE}.txt"
if [ $EXIT_CODE -ne 0 ]; then
echo "ALERTE : ${server} ne respecte pas la politique de sécurité" | tee -a "${REPORT_DIR}/rapport_${DATE}.txt"
FAILURES=$((FAILURES + 1))
fi
echo "" | tee -a "${REPORT_DIR}/rapport_${DATE}.txt"
done < "${SERVERS_FILE}"
# Envoyer une alerte si des serveurs échouent
if [ $FAILURES -gt 0 ]; then
echo "${FAILURES} serveur(s) non conforme(s) détecté(s)." | \
mail -s "[ALERTE SSH] ${FAILURES} serveur(s) non conforme(s) - ${DATE}" "${ALERT_EMAIL}" < "${REPORT_DIR}/rapport_${DATE}.txt"
fi
echo "Audit terminé. ${FAILURES} non-conformité(s) détectée(s)."
Défense active contre les attaques par force brute
CrowdSec : l'intelligence collective contre les attaques
CrowdSec est le successeur moderne de Fail2Ban, et honnêtement, c'est un sacré pas en avant. Là où Fail2Ban se contente de lire les journaux locaux pour bannir les IP, CrowdSec ajoute une dimension communautaire : les IP malveillantes détectées par un serveur sont partagées avec l'ensemble de la communauté. On parle d'une base de données de menaces en temps réel alimentée par des centaines de milliers de serveurs.
# Installation de CrowdSec sur Debian/Ubuntu
curl -s https://install.crowdsec.net | sudo bash
sudo apt install crowdsec crowdsec-firewall-bouncer-iptables
# Sur RHEL/Fedora
curl -s https://install.crowdsec.net | sudo bash
sudo dnf install crowdsec crowdsec-firewall-bouncer-iptables
# Vérifier l'installation
sudo cscli version
sudo cscli metrics
# Installer la collection SSH
sudo cscli collections install crowdsecurity/sshd
# Vérifier les scénarios actifs
sudo cscli scenarios list
# Voir les décisions en cours (IP bannies)
sudo cscli decisions list
# Consulter les alertes récentes
sudo cscli alerts list
Configuration avancée de CrowdSec pour SSH
# /etc/crowdsec/acquis.yaml - Sources de logs
---
filenames:
- /var/log/auth.log
- /var/log/secure
labels:
type: syslog
---
source: journalctl
journalctl_filter:
- "_SYSTEMD_UNIT=sshd.service"
labels:
type: syslog
# Personnaliser les seuils de détection
# /etc/crowdsec/scenarios/custom-ssh-bf.yaml
type: leaky
name: custom/ssh-bruteforce-strict
description: "Détection stricte de force brute SSH"
filter: "evt.Meta.log_type == 'ssh_failed-auth'"
groupby: evt.Meta.source_ip
capacity: 3
leakspeed: "2m"
blackhole: 12h
labels:
remediation: true
type: bruteforce
service: ssh
Fail2Ban : la solution éprouvée
Si vous préférez une solution plus simple et sans dépendance communautaire, Fail2Ban reste tout à fait solide. Il fait le job depuis des années et continue de bien le faire. Voici une configuration durcie :
# /etc/fail2ban/jail.local
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 3
banaction = nftables-multiport
banaction_allports = nftables-allports
[sshd]
enabled = true
port = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)s
maxretry = 3
findtime = 300
bantime = 86400
# Bannissement progressif
[sshd-aggressive]
enabled = true
port = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)s
maxretry = 1
findtime = 86400
bantime = 604800
filter = sshd[mode=aggressive]
SSHGuard : léger et spécialisé
SSHGuard est une alternative plus légère, conçue spécifiquement pour protéger SSH. Contrairement à Fail2Ban qui analyse les logs avec des expressions régulières (ce qui peut être gourmand), SSHGuard utilise un parseur intégré bien plus efficace :
# Installation
sudo apt install sshguard # Debian/Ubuntu
sudo dnf install sshguard # Fedora/RHEL
# Configuration avec nftables
# /etc/sshguard/sshguard.conf
BACKEND="/usr/libexec/sshguard/sshg-fw-nft-sets"
LOGREADER="LANG=C /usr/bin/journalctl -afb -p info -n1 -t sshd -o cat"
# Seuil d'attaque : 30 points (chaque tentative = 10 points)
THRESHOLD=30
# Durée de blocage initiale : 120 secondes
BLOCK_TIME=120
# Multiplicateur de blocage pour les récidivistes
DETECTION_TIME=3600
# Liste blanche
WHITELIST_FILE=/etc/sshguard/whitelist
Endlessh : le pot de miel SSH
Endlessh est probablement l'outil le plus amusant de cette liste. C'est un tarpit SSH — un pot de miel qui ralentit les attaquants en envoyant une bannière SSH infinie, très lentement. Les scanners automatisés restent bloqués pendant des heures, gaspillant leurs ressources au lieu d'attaquer vos vrais services. Il y a quelque chose de satisfaisant à voir un bot tourner en rond.
# Installation depuis les sources
git clone https://github.com/skeeto/endlessh.git
cd endlessh
make
sudo cp endlessh /usr/local/bin/
# Configuration
# /etc/endlessh/config
Port 22 # Port leurre (déplacer le vrai SSH sur un autre port)
Delay 10000 # Délai entre chaque ligne (ms)
MaxLineLength 32 # Longueur max de chaque ligne
MaxClients 4096 # Nombre max de connexions simultanées
LogLevel 1 # Journalisation
# Service systemd
sudo cp util/endlessh.service /etc/systemd/system/
sudo systemctl enable --now endlessh
# Déplacer le vrai SSH sur un port non standard
# /etc/ssh/sshd_config
Port 2222
# Redémarrer SSH
sudo systemctl restart sshd
Surveillance et journalisation avancée
Journalisation structurée avec journald
OpenSSH avec LogLevel VERBOSE produit des journaux détaillés, mais encore faut-il savoir les exploiter. Voici comment tirer le meilleur parti de la journalisation SSH :
# Consulter les événements SSH en temps réel
journalctl -u sshd -f --output=json-pretty
# Rechercher les connexions réussies
journalctl -u sshd | grep "Accepted"
# Rechercher les échecs d'authentification
journalctl -u sshd | grep "Failed\|Invalid\|refused"
# Statistiques des connexions sur les dernières 24 heures
journalctl -u sshd --since "24 hours ago" | grep "Accepted" | \
awk '{print $9, $11}' | sort | uniq -c | sort -rn
# Exporter vers un SIEM (exemple avec rsyslog vers un serveur distant)
# /etc/rsyslog.d/50-ssh-remote.conf
:programname, isequal, "sshd" @@siem.mondomaine.fr:514
Détection des comportements suspects
Pour aller plus loin, voici un script de détection d'anomalies qui peut être exécuté en cron. Il est loin d'être parfait (un vrai SIEM fera toujours mieux), mais il donne déjà une bonne visibilité :
#!/bin/bash
# Script de détection d'anomalies SSH
# detect_ssh_anomalies.sh
LOG_FILE="/var/log/auth.log"
ALERT_THRESHOLD=50
WATCH_PERIOD="1 hour ago"
echo "=== Détection d'anomalies SSH ==="
# 1. IP avec le plus de tentatives échouées
echo -e "\n--- Top 10 IP attaquantes ---"
journalctl -u sshd --since "${WATCH_PERIOD}" | \
grep "Failed password\|Invalid user" | \
grep -oP 'from \K[0-9.]+' | \
sort | uniq -c | sort -rn | head -10
# 2. Noms d'utilisateur les plus ciblés
echo -e "\n--- Utilisateurs ciblés ---"
journalctl -u sshd --since "${WATCH_PERIOD}" | \
grep "Failed password\|Invalid user" | \
grep -oP 'for (invalid user )?\K\S+' | \
sort | uniq -c | sort -rn | head -10
# 3. Connexions depuis des pays inhabituels (nécessite geoiplookup)
echo -e "\n--- Connexions par pays ---"
journalctl -u sshd --since "${WATCH_PERIOD}" | \
grep "Accepted" | \
grep -oP 'from \K[0-9.]+' | \
while read ip; do
COUNTRY=$(geoiplookup "$ip" 2>/dev/null | head -1 | awk -F": " '{print $2}')
echo "$ip - $COUNTRY"
done | sort | uniq -c | sort -rn
# 4. Connexions en dehors des heures de bureau
echo -e "\n--- Connexions hors horaires (avant 7h ou après 20h) ---"
journalctl -u sshd --since "${WATCH_PERIOD}" | \
grep "Accepted" | \
awk '{split($3,t,":"); if(t[1]<7 || t[1]>20) print $0}'
Gestion du cycle de vie des clés SSH
Rotation régulière des clés hôte
Les clés hôte SSH devraient être renouvelées périodiquement — en particulier après tout incident de sécurité, même suspecté. Voici un script qui automatise cette rotation :
#!/bin/bash
# Script de rotation des clés hôte SSH
# rotate_host_keys.sh
set -euo pipefail
BACKUP_DIR="/root/ssh_keys_backup/$(date +%Y%m%d_%H%M%S)"
mkdir -p "${BACKUP_DIR}"
echo "=== Rotation des clés hôte SSH ==="
# Sauvegarder les anciennes clés
echo "1. Sauvegarde des clés existantes..."
cp /etc/ssh/ssh_host_* "${BACKUP_DIR}/"
chmod 700 "${BACKUP_DIR}"
# Générer de nouvelles clés
echo "2. Génération des nouvelles clés..."
rm -f /etc/ssh/ssh_host_*
ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N "" -q
ssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key -N "" -q
echo "3. Nouvelles empreintes de clés :"
ssh-keygen -l -f /etc/ssh/ssh_host_ed25519_key.pub
ssh-keygen -l -f /etc/ssh/ssh_host_rsa_key.pub
# Si vous utilisez des certificats hôte, re-signer avec la CA
if [ -f /etc/ssh/ca/host_ca ]; then
echo "4. Re-signature du certificat hôte..."
HOSTNAME=$(hostname -f)
ssh-keygen -s /etc/ssh/ca/host_ca \
-I "${HOSTNAME}" \
-h \
-n "${HOSTNAME},$(hostname -s),$(hostname -I | tr ' ' ',')" \
-V +52w \
/etc/ssh/ssh_host_ed25519_key.pub
echo " Certificat re-signé avec succès."
fi
# Redémarrer SSH
echo "5. Redémarrage de sshd..."
systemctl restart sshd
echo "=== Rotation terminée ==="
echo "IMPORTANT : Les clients devront accepter les nouvelles clés hôte."
echo "Si vous utilisez des certificats, les clients n'auront pas d'avertissement."
Inventaire et audit des clés utilisateurs
Savoir quelles clés sont déployées sur quels serveurs, c'est la base. Et pourtant, dans la pratique, c'est souvent le grand flou. Ce script d'inventaire vous donne une vue d'ensemble :
#!/bin/bash
# Script d'inventaire des clés SSH utilisateurs
# inventory_ssh_keys.sh
echo "=== Inventaire des clés SSH autorisées ==="
echo "Date : $(date)"
echo ""
printf "%-20s %-10s %-15s %-50s\n" "UTILISATEUR" "TYPE" "TAILLE" "COMMENTAIRE"
printf "%s\n" "$(printf '=%.0s' {1..95})"
# Parcourir tous les répertoires home
for home_dir in /home/*/; do
user=$(basename "${home_dir}")
auth_keys="${home_dir}.ssh/authorized_keys"
if [ -f "${auth_keys}" ]; then
while IFS= read -r line; do
# Ignorer les lignes vides et les commentaires
[[ -z "$line" || "$line" =~ ^# ]] && continue
KEY_TYPE=$(echo "$line" | awk '{print $1}')
COMMENT=$(echo "$line" | awk '{print $3}')
# Déterminer la taille de la clé
KEY_SIZE=$(echo "$line" | ssh-keygen -l -f - 2>/dev/null | awk '{print $1}' || echo "N/A")
printf "%-20s %-10s %-15s %-50s\n" \
"$user" "$KEY_TYPE" "$KEY_SIZE" "${COMMENT:-(sans commentaire)}"
done < "${auth_keys}"
fi
done
# Vérifier les clés potentiellement dangereuses
echo ""
echo "=== Alertes de sécurité ==="
# Clés DSA (obsolètes)
echo "--- Clés DSA (à supprimer immédiatement) ---"
grep -rl "ssh-dss" /home/*/.ssh/authorized_keys 2>/dev/null || echo "Aucune clé DSA détectée."
# Clés RSA de taille insuffisante
echo "--- Clés RSA < 3072 bits ---"
for auth_keys in /home/*/.ssh/authorized_keys; do
[ -f "$auth_keys" ] || continue
while IFS= read -r line; do
[[ -z "$line" || "$line" =~ ^# ]] && continue
echo "$line" | ssh-keygen -l -f - 2>/dev/null | awk '$1 < 3072 && /RSA/ {print FILENAME": "$0}' FILENAME="$auth_keys"
done < "$auth_keys"
done
echo ""
echo "Inventaire terminé."
Checklist de durcissement SSH
Pour ceux qui veulent aller droit à l'essentiel, voici un récapitulatif des mesures à mettre en place, classées par priorité. Imprimez-le, affichez-le au mur — faites-en ce que vous voulez, mais suivez-le.
Priorité critique
- Désactiver l'authentification par mot de passe (
PasswordAuthentication no) - Interdire la connexion root (
PermitRootLogin no) - Supprimer toute clé DSA résiduelle
- Mettre à jour vers OpenSSH 10.x pour la cryptographie post-quantique par défaut
- Configurer des algorithmes cryptographiques forts (voir notre configuration ci-dessus)
Priorité haute
- Déployer des clés FIDO2 matérielles pour les administrateurs
- Mettre en place CrowdSec ou Fail2Ban contre les attaques par force brute
- Limiter l'accès SSH à un groupe spécifique (
AllowGroups ssh-users) - Configurer
MaxAuthTries 3etMaxStartups 10:30:60 - Activer la journalisation détaillée (
LogLevel VERBOSE)
Priorité moyenne
- Implémenter les certificats SSH pour remplacer
authorized_keys - Auditer régulièrement la configuration avec ssh-audit
- Mettre en place un bastion SSH (jump host) pour centraliser les accès
- Désactiver tout forwarding non nécessaire (X11, TCP, agent)
- Configurer une bannière légale d'avertissement
Priorité recommandée
- Automatiser la rotation des clés hôte
- Déployer Endlessh comme pot de miel sur le port 22
- Maintenir un inventaire des clés SSH autorisées
- Centraliser les journaux SSH vers un SIEM
- Tester régulièrement votre configuration avec des outils de pentest
Conclusion : la sécurité SSH, un travail de tous les jours
Le durcissement SSH en 2026 ne se résume plus à changer le port par défaut et à désactiver les mots de passe. Avec OpenSSH 10, la cryptographie post-quantique par défaut, la séparation architecturale du code d'authentification, les clés matérielles FIDO2 et les certificats à durée de vie courte, on dispose d'un arsenal de défense sans précédent.
La clé du succès, c'est la défense en profondeur. Chaque couche de protection — configuration durcie, authentification forte, détection d'intrusion, surveillance active — compense les faiblesses potentielles des autres. Un attaquant ne peut pas forcer un mot de passe si l'authentification par mot de passe est désactivée. Il ne peut pas voler une clé privée si elle est stockée sur un dispositif matériel FIDO2. Il ne peut pas exploiter un algorithme faible si seuls les algorithmes post-quantiques sont activés.
La menace quantique, bien qu'encore à quelques années de nous, justifie dès aujourd'hui la migration vers les algorithmes hybrides. Le principe « récolter maintenant, déchiffrer plus tard » rend cette transition urgente pour toute organisation manipulant des données sensibles. Et avec OpenSSH 10, cette migration est devenue triviale — les algorithmes post-quantiques sont activés par défaut.
Enfin, n'oubliez pas que la sécurité est un processus continu, pas un état final. Auditez régulièrement vos configurations, surveillez vos journaux, effectuez la rotation de vos clés, et restez informés des nouvelles vulnérabilités. Votre infrastructure mérite une sécurité SSH à la hauteur des menaces actuelles — et de celles qui arrivent.