OpenSSH :: Fricouv.eu

OpenSSH

Je réitère, le contenu de ce billet n’est que l’expression de ma piètre opinion et de ma piètre technicité en terme de sécu (je me considèrerais toujours comme un éternel débutant).

OpenSSH, personne ne le présente plus, pour l’intégralité des admins GNU/Linux, c’est quelque chose de connu et d’utilisé au quotidien.

Par contre, on va parler de comment sécuriser un peu ce service qui est pour le moins sensible.
Attention : cette configuration nécessite que vous utilisiez une clef ssh au format ED25519 pour vous connecter à votre machine

Les fausse rumeurs

Pour sécuriser OpenSSH, on voit souvent passer des choses comme « Il faut changer le port d’écoute ».
Alors oui, mais non. Enfin… Presque non on va dire.

Pour ma part, je ne pense absolument pas que changer le port d’écoute d’OpenSSH ait une quelconque utilité au niveau sécurité.
Pourquoi ? Et bien simplement parce que les scans de ports pour découvrir les services qui tourent sur une machine ne se limite plus aux ports connus.
Si cette action était vrai il y a longtemps, elle ne l’est plus maintenant au vu des attaquants.

Changer un port d’écoute permet au mieux de délayer très temporairement le début de l’attaque, pas plus, pas moins (À part permettre de passer des firewalls peut-être ?).

Comment qu’on fait du coup ?

Et bien c’est simple sans vraiment l’être, pour plusieurs raisons, parce qu’il faut un minimum savoir ce qu’on fait déjà, et parce qu’il faut comprendre un peu les mécanismes d’attaque (chose sur laquelle je ne vais pas vraiment m’attarder).

La configuration d’OpenSSH regorge déjà de beaucoup de choses permettant de « blinder » votre service. Il faut juste les adapter à vos besoin et à ce qui permettra de fermer des portes inutiles (réduction de la surface d’attaque).

Le cas Debian

Oui je prends le cas de Debian pour example parce que c’est l’OS server que j’utilise le plus, mais c’est valable pour beaucoup d’autres distributions.

Config d’usine

Si on prends le fichier /etc/ssh/sshd_config de base out-of-box de Debian on se retrouve avec le fichier de configuration suivant :

#Port 22
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::

#HostKey /etc/ssh/ssh_host_rsa_key
#HostKey /etc/ssh/ssh_host_ecdsa_key
#HostKey /etc/ssh/ssh_host_ed25519_key

# Ciphers and keying
#RekeyLimit default none

#SyslogFacility AUTH
#LogLevel INFO

#LoginGraceTime 2m
#PermitRootLogin prohibit-password
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10

#PubkeyAuthentication yes

#AuthorizedKeysFile	.ssh/authorized_keys .ssh/authorized_keys2

#AuthorizedPrincipalsFile none

#AuthorizedKeysCommand none
#AuthorizedKeysCommandUser nobody

#HostbasedAuthentication no
#IgnoreUserKnownHosts no
#IgnoreRhosts yes
#PasswordAuthentication yes
#PermitEmptyPasswords no
ChallengeResponseAuthentication no
#KerberosAuthentication no
#KerberosOrLocalPasswd yes
#KerberosTicketCleanup yes
#KerberosGetAFSToken no
#GSSAPIAuthentication no
#GSSAPICleanupCredentials yes
#GSSAPIStrictAcceptorCheck yes
#GSSAPIKeyExchange no
UsePAM yes

#AllowAgentForwarding yes
#AllowTcpForwarding yes
#GatewayPorts no
X11Forwarding yes
#X11DisplayOffset 10
#X11UseLocalhost yes
#PermitTTY yes
PrintMotd no
#PrintLastLog yes
#TCPKeepAlive yes
#PermitUserEnvironment no
#Compression delayed
#ClientAliveInterval 0
#ClientAliveCountMax 3
#UseDNS no
#PidFile /var/run/sshd.pid
#MaxStartups 10:30:100
#PermitTunnel no
#ChrootDirectory none
#VersionAddendum none

#Banner none

AcceptEnv LANG LC_*

Subsystem	sftp	/usr/lib/openssh/sftp-server

Pour rappel, toutes les lignes avec des # devant correspondent aux configurations « built-in » non surchargé.
En faisant un tour rapide, on voit :

Option(s) Description
Port, AddressFamily, ListenAddress Le service écoute sur le port 22, sur toutes les IP (v4 et v6)
HostKey Le service sert des clefs host de type RSA, ECDSA et ED25519
RekeyLimit Le service ne renégocie pas de clefs de session quel que soit le volume de données échangé
LoginGraceTime Le service laisse 2m pour s’authentifier lors de la demande de connexion
PermitRootLogin Le service laisse se connecter avec l’utilisateur root si on arrive avec une clefs ssh uniquement
StrictModes Le service vérifie les droits sur les fichiers qu’il utilise
MaxAuthTries Le service autorise 6 tentatives de connexions avant de couper
MaxSessions Le service autorise 10 sessions simultanées
PubkeyAuthentication Le service autorise l’authentification par clefs
HostbasedAuthentication Le service ne vérifie pas que le host qui se connecte est autorisé
IgnoreRhosts Le service ne regarde pas si l’utilisateur qui se connecte vient d’un host déclaré et autorisé
PasswordAuthentication Le service autorise les connexions par mot de passe
KerberosAuthentication Le service n’autorise pas l’authentification via Kerberos
GSSAPIAUthentication Le service n’autorise pas l’authentification via GSSAPI
UsePAM Le service autorise l’authentification via pam
AllowAgentForwarding Le service autorise le forward des agents ssh
AllowTcpForwarding Le service autorise le forward TCP
X11Forwarding Le service autorise le forward X11
PermitTunnel Le service n’autorise pas les tunnels
ChrootDirectory Le service ne chroote pas les utilisateurs
Subsystem Le service autorise le service sftp

Ouai ça en fait beaucoup des options… Mais on va faire le ménage !

Qu’est-ce qu’on garde, qu’est-ce qu’on vire ?

On peut faire le tri dans beaucoup d’options si elles n’ont pas d’utilité dans le contexte. Je pense notamment à :

  • HostbasedAuthentication et IgnoreRhost : utilité uniquement dans un contexte pleinement connus (qui doit se connecter et depuis où)
  • KerberosAuthentication et GSSAPIAuthentication : utilité uniquement si vous souhaitez utiliser ces méthodes de connexion
  • ChrootDirectory : utilité uniquement si vous avez beaucoup d’users non connus et non maitrisé qui se connectent
  • ListenAddress et AddressFamily : Le but c’est de pouvoir se connecter au serveur non ? Donc par défaut ça va bien
  • PermitEmptyPasswords : Par défaut ça me va bien de ne pas authoriser les passwords vides

Déjà avec ça, on a fait un bon petit tris dans les blocs et dans les options du fichier pour avoir quelque chose qui ressemble à ça :

#Port 22

#HostKey /etc/ssh/ssh_host_rsa_key
#HostKey /etc/ssh/ssh_host_ecdsa_key
#HostKey /etc/ssh/ssh_host_ed25519_key

# Ciphers and keying
#RekeyLimit default none

#SyslogFacility AUTH
#LogLevel INFO

#LoginGraceTime 2m
#PermitRootLogin prohibit-password
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10

#PubkeyAuthentication yes

#PasswordAuthentication yes
ChallengeResponseAuthentication no
UsePAM yes

#AllowAgentForwarding yes
#AllowTcpForwarding yes
X11Forwarding yes
#X11DisplayOffset 10
#TCPKeepAlive yes
#Compression delayed
#PermitTunnel no

AcceptEnv LANG LC_*

Subsystem	sftp	/usr/lib/openssh/sftp-server

Déjà plus petit. Maintenant, qu’est-ce qu’on change pour sécuriser un peu tout le bordel ?

Sécurisation de la configuration d’origine

Il y a déjà un certain nombre d’options qui sont correcte avec le paramétrage de base et qu’on ne va pas vouloir modifier hors contexte particulier. Donc on va décommenter ce qu’on veut forcément activer pour être sur que c’est actif :

Port 22
HostKey /etc/ssh/ssh_host_ed25519_key
SyslogFacility AUTH
LogLevel INFO
StrictModes yes
PubkeyAuthentication yes
TCPKeepAlive yes
PermitTunnel no

Déjà, premère étape terminé. La seule différence que l’on induit est sur la partie HostKey. Pourquoi ? Et bien simplement, plutôt que de servir trois types de clefs comme il fait d’origine, le service ne servira plus qu’on type de clef ed25519 qui est à ce jour l’un des algos les plus sur qui existe.
Mais on va revenir un peu après sur cette fameuse clef.

Ensuite, il y a des chose dont vous n’aurez probablement jamais besoin sur un serveur :

Option Default Sécurisé Description
PermitRootLogin prohibit-password no On n’autorise pas les connexions root directes. Pour pouvoir tracer qui se connecte, mais aussi pour éviter un accès direct à l’utilisateur de plus haut privilèges possible
LoginGraceTime 2m 30s Vous avez réellement besoin de 2 minutes pour vous connecter en ssh ?
MaxAuthTries 6 2 Deux échecs de connexions c’est suffisant pour vous foutre dehors je pense
MaxSessions 10 5 Besoin de plus de 5 connexions simultané sur la même machine ?
PasswordAuthentication yes no Perso, je n’autorise personne à se connecter avec un mot de passe, clef uniquement
AllowAgentForwarding yes no Si votre serveur n’a pas vocation à servir de rebon, aucun intéret d’utiliser un agent ssh, on désactive donc pour éviter la propagation de vos clefs SSH pour rien
AllowTcpForwarding yes no Idem qu’au dessus, si votre serveur n’a pas vocation à servir de point d’entrée pour accéder à d’autres service, on bloque le TCP Forwarding pour éviter des effets de bord bizarres
X11Forwarding yes no Vous avez un environnement graphique sur votre serveur et des applis graphiques ? Moi non, du coup, adieux le X11 forwarding
Compression delayed yes Alors là on est pas sur de la « sécu », juste sur de l’optimisation de flux, je compresse mes connexions SSH, c’est quasi transparent au niveau usage et ça fait économiser de la bande passante

Bon, avec tout ça, on en est là :

Port 22

#HostKey /etc/ssh/ssh_host_rsa_key
#HostKey /etc/ssh/ssh_host_ecdsa_key
HostKey /etc/ssh/ssh_host_ed25519_key

# Ciphers and keying
#RekeyLimit default none

SyslogFacility AUTH
LogLevel INFO

LoginGraceTime 30s
PermitRootLogin no
StrictModes yes
MaxAuthTries 2
MaxSessions 5

PubkeyAuthentication yes

PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM yes

AllowAgentForwarding no
AllowTcpForwarding no
X11Forwarding no
TCPKeepAlive yes
Compression yes
PermitTunnel no

AcceptEnv LANG LC_*

Subsystem	sftp	/usr/lib/openssh/sftp-server

Reste deux choses dont je n’ai pas parlé, c’est le RekeyLimit, et vu que je n’ai jamais utilisé encore, je ne vais pas en parler, et le Subsystem.
Ce dernier vous permettant d’utiliser le sous-système SFTP pour pouvoir transférer des fichiers via une session SSH.

Là c’est une question d’usage, si on cause sécu de ce bout là, je vous conseille de regarder via du matching pour ne déclencher le subsystem que pour certains users/hosts. Je ne vais pas m’attarder dessus, c’est pleinement fonctionnel et lié à la sécurité d’OpenSSH, donc pas trop de craintes à avoir, c’est purement de l’usage, si ce n’est pas utile, virez le, si c’est utile pour tous, laissez le, si ce n’est utile que pour certains, metchez le.

Sécurisation avancé

Nous avons déjà fait un bon gros bout de sécurisation du service OpenSSH avec ce qui est fournis par défaut dans le fichier de configuration de Debian. Mais il reste pas mal de chose que l’on peut rajouter, et typiquement sur les algos de chiffrement, ce qui aura pour effet de casser énorméments de robots de scan qui tournent et d’élever les sécurités de votre service pour des clients à jour.

Attention cette configuration est impactante avec des clients non à jour, donc ça peut dans certains cas casser des applis qui utilisent le SSH, à vous de faire attention et de tuner (à l’aide des logs d’OpenSSH) les bonnes configurations pour vos usages.

Trois options donc à traiter :

Option Description
Ciphers Spécifie les méthodes de chiffrement autorisés
MACs Spécifie les algorythmes messages d’authentification autorisés (gère l’intégrité des messages échangés)
KexAlgorithms Spécifie les algorythmes de méthodes d’échange de clefs

Ces trois options, je suis un peu « abusif » dessus, mais en fait, vu que mes services SSH ne servent que pour de la gestion à distance, ce n’est pas grave, je peux me permettre d’être « violent » sur ces paramètres.

Du coup, j’ai ça comme configuration pour ces trois options (qui sont les plus hautes possible) :

Ciphers chacha20-poly1305@openssh.com
MACs umac-128-etm@openssh.com
KexAlgorithms curve25519-sha256@libssh.org

Si vous souhaitez mettre des algos en plus, je vous invite à vous référer à la documentation sshd_config d’OpenBSD

Bon ben voilà, c’est l’heure du récap

Régénération clef host

Je vous ai parlé plus haut de la fameuse « HostKey ». J’y revient dessus maintenant.

Déjà le choix de ne servir que de l’ED25519, je pense que vous l’avez compris avant d’arriver ici.
Maintenant, je vais vous montrer comment regénérer cette clef pour être sur de sa longueur et ainsi avoir une clef suffisamment conséquente pour éviter qu’elle soit « cassable ».

La procédure est vraiment très simple, c’est une seule commande :

ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -b 521

Vous voilà avec une bonne grosse clef éliptique pour identifier l’hôte OpenSSH.

Récapitulatif

Donc nous avons passé toutes les options nécessaires pour sécuriser le service OpenSSH afin qu’il soit le moins exposé possible.

Si on récapitule le fichier final, il devrait ressembler à quelque chose comme ça :

Port 22

HostKey /etc/ssh/ssh_host_ed25519_key

# Ciphers and keying
#RekeyLimit default none
Ciphers chacha20-poly1305@openssh.com
MACs umac-128-etm@openssh.com
KexAlgorithms curve25519-sha256@libssh.org

SyslogFacility AUTH
LogLevel INFO

LoginGraceTime 30s
PermitRootLogin no
StrictModes yes
MaxAuthTries 2
MaxSessions 5

PubkeyAuthentication yes

PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM yes

AllowAgentForwarding no
AllowTcpForwarding no
X11Forwarding no
TCPKeepAlive yes
Compression yes
PermitTunnel no

AcceptEnv LANG LC_*

Subsystem	sftp	/usr/lib/openssh/sftp-server

Avec ça, vous êtes vraiment pas mal !
Il reste toute fois deux choses que l’on pourrait ajouter.

La première c’est d’ajouter un fail2ban pour filtrer correctement les tentatives de connexion infructueuse et ainsi bannir les hosts qui tente de se connecter sans y arriver.
La deuxième est purement réseau et c’est du bon sens, c’est de limiter (via le firewall local où via un firewall d’infrastructure) quelles sont les adresses IP autorisé à se connecter au serveur SSH. Après, il arrive que celà ne soit pas possible à réaliser, et c’est là tout l’intéret de cette configuration car elle vous prémunit un maximum de prise de controle de votre serveur. Je tiens quand même à repréciser que rien n’est infaillible, et que je ne peux en aucun cas être tenu pour responsable si un serveur se fait compromettre même avec cette configuration.