Comment configurer un bastion SSH

Un bastion est un petit serveur qui accepte SSH depuis l'extérieur et ne le redirige que vers vos serveurs internes. Donnez à ses utilisateurs un groupe avec AllowTcpForwarding local, PermitOpen listant les cibles autorisées, PermitTTY no et ForceCommand /usr/sbin/nologin, dans un bloc Match Group, avec la redirection désactivée pour tous les autres. Les utilisateurs se connectent ensuite avec ssh -J user@bastion user@internal. Ne réglez pas DisableForwarding yes pour eux, car cela bloque aussi le rebond.

Mis à jour le . Cette configuration a été exécutée avec OpenSSH 10.0 sur Debian 13, avec deux conteneurs jetables comme bastion et cible.

Ce qu'il doit être

  • Un petit serveur séparé qui exécute SSH et rien d'autre : pas de base de données, pas de site web, pas d'outils de développement.
  • Des clés uniquement, avec des mises à jour de sécurité automatiques.
  • Aucune clé privée dessus. Un rebond rend cela inutile. La connexion au serveur interne est chiffrée depuis votre propre machine, et le bastion ne fait que faire passer les données.
  • Le seul point d'entrée. Les serveurs internes ne doivent accepter SSH que depuis l'adresse du bastion, au niveau du pare-feu.

Pour le reste des réglages SSH du serveur, voir comment durcir sshd_config.

Créer les utilisateurs

sudo groupadd jump
sudo useradd -m -G jump -s /bin/bash alice
sudo install -d -m 700 -o alice -g alice /home/alice/.ssh
sudo install -m 600 -o alice -g alice alice.pub /home/alice/.ssh/authorized_keys

Gardez votre propre compte d'administration hors du groupe jump, pour conserver un shell.

La configuration de sshd

# /etc/ssh/sshd_config.d/10-bastion.conf
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
AllowAgentForwarding no
AllowTcpForwarding no
AllowStreamLocalForwarding no
X11Forwarding no
PermitTunnel no
GatewayPorts no
LogLevel VERBOSE

Match Group jump
    AllowTcpForwarding local
    PermitOpen 10.0.1.10:22 10.0.1.11:22
    PermitTTY no
    ForceCommand /usr/sbin/nologin

Chaque réglage du bloc a un rôle :

  • AllowTcpForwarding local autorise les rebonds et -L, mais pas -R.
  • PermitOpen liste les destinations possibles. Énumérez chaque serveur : * peut remplacer un hôte ou un port entier, mais pas une partie d'adresse comme 10.0.1.*.
  • PermitTTY no et ForceCommand suppriment le shell. ForceCommand seul n'empêche pas la redirection, et c'est ce qui lui permet de fonctionner ici.

Placez-le dans un fichier à part sous /etc/ssh/sshd_config.d/, et vérifiez d'abord qu'aucun autre fichier ne définit les mêmes options avant lui : sshd garde la première valeur lue. Un bloc Match dans un tel fichier s'arrête à la fin du fichier. Vérifiez ensuite et rechargez, en laissant une session ouverte :

sudo sshd -t
sudo sshd -T -C user=alice,host=client,addr=203.0.113.10 | grep -iE '^(allowtcpforwarding|permitopen|permittty|forcecommand) '
sudo systemctl reload ssh
permittty no
allowtcpforwarding local
forcecommand /usr/sbin/nologin
permitopen 10.0.1.10:22 10.0.1.11:22

Le chemin de nologin peut être /sbin/nologin sur d'autres systèmes : vérifiez-le avec command -v nologin.

DisableForwarding est pour les autres utilisateurs

DisableForwarding yes désactive toute redirection et l'emporte sur les autres réglages : il convient donc à un groupe qui ne doit jamais rien rediriger. Ne l'utilisez pas pour les utilisateurs de rebond. Un rebond est une redirection, et dans notre essai il a échoué avec stdio forwarding failed.

Se connecter par son intermédiaire

ssh -J alice@bastion.example.com user@10.0.1.10

Ou, pour moins taper, dans ~/.ssh/config sur votre propre machine :

Host bastion
    HostName bastion.example.com
    User alice

Host app1
    HostName 10.0.1.10
    User user
    ProxyJump bastion

Lancez ensuite ssh app1. Votre clé doit se trouver à la fois sur le bastion et sur le serveur interne. Le côté client est détaillé dans hôtes de rebond et ProxyJump. Évitez ForwardAgent, pour les raisons données dans les risques de la redirection d'agent.

Tester ce qui est refusé

Voici les résultats obtenus avec cette configuration, et vous devriez voir les mêmes :

TestRésultat
ssh -J alice@bastion user@10.0.1.10Connecté au serveur interne
ssh -W 10.0.1.10:80 alice@bastionstdio forwarding failed
ssh -tt alice@bastionPTY allocation request failed on channel 0
ssh alice@bastion idThis account is currently not available.
ssh -N -o ExitOnForwardFailure=yes -R 8080:localhost:22 alice@bastionError: remote port forwarding failed for listen port 8080

Journalisation : ce que vous obtenez et ce que vous n'obtenez pas

Dès le niveau par défaut, chaque connexion est enregistrée avec l'empreinte de sa clé, ce qui indique qui s'est connecté. LogLevel VERBOSE enregistre aussi les clés refusées. Une connexion ressemble à ceci :

Accepted publickey for alice from 203.0.113.10 port 51018 ssh2: ED25519 SHA256:NxFS05Q+k1zf...

Les cibles refusées sont aussi journalisées :

Received request from 203.0.113.10 port 51036 to connect to host 10.0.1.10 port 80, but the request was denied.

Les cibles réussies ne le sont pas, en INFO ou VERBOSE. Nous avons vérifié : le journal du bastion montre qu'alice s'est connectée, mais pas vers quel serveur elle est allée ensuite. Dans notre essai, cela n'apparaissait qu'à LogLevel DEBUG1, et le manuel prévient que les niveaux de débogage peuvent enregistrer des détails privés des utilisateurs :

debug1: server_request_direct_tcpip: originator 127.0.0.1 port 65535, target 10.0.1.10 port 22

Lisez donc les deux côtés. Le journal du serveur interne montre qui s'est connecté et avec quelle clé, avec l'adresse du bastion comme source. Rapprochez les deux par l'heure, et envoyez les deux vers une machine extérieure au bastion, car un attaquant ayant root dessus pourrait modifier la copie locale. Voir comment vérifier les tentatives de connexion pour lire ces journaux.

Retirer l'accès

Retirez la clé publique de l'utilisateur du bastion, et il perd cette voie vers tous les serveurs derrière. Il peut encore utiliser tout serveur interne qu'il atteint autrement : retirez donc aussi la clé là. Voir comment révoquer une clé.

Questions

Quelle différence entre un bastion et un hôte de rebond ?

Peu. Un hôte de rebond est tout serveur par lequel on passe pour en atteindre un autre. Un bastion est un hôte de rebond configuré et durci pour cette seule tâche, et c'est la seule entrée depuis l'extérieur.

Le bastion a-t-il besoin de ma clé privée ?

Non. Avec ProxyJump, la connexion au serveur interne part de votre machine et reste chiffrée de bout en bout. Le bastion ne fait que relayer la connexion.

Pourquoi ssh -J échoue-t-il avec stdio forwarding failed ?

Le bastion a refusé la redirection. Vérifiez que AllowTcpForwarding l'autorise pour votre utilisateur, que la cible figure dans PermitOpen et que DisableForwarding n'est pas activé.

Sources

Autres guides : Tunnels et hôtes de rebond

Tous les guides