Aller au contenu

SSH : tunnels et rebonds

Un tunnel SSH fait passer un trafic réseau dans une connexion chiffrée. Les exemples utilisent un serveur monserveur (alias défini dans Configuration du client).

Redirection locale (-L) : atteindre un service distant

Section intitulée « Redirection locale (-L) : atteindre un service distant »

Donne accès, depuis le poste local, à un port vu depuis le serveur (par exemple une base de données qui n’écoute qu’en local) :

Fenêtre de terminal
ssh -N -L 5432:127.0.0.1:5432 monserveur
Élément Signification
-L 5432:127.0.0.1:5432 Port local 5432 → adresse 127.0.0.1:5432 vue du serveur
-N Ne lance pas de commande (tunnel seul)
-f Passe en arrière-plan après l’authentification

Pendant que la commande tourne :

Fenêtre de terminal
psql -h 127.0.0.1 -p 5432 -U app boutique # se connecte à PostgreSQL du serveur
mysql -h 127.0.0.1 -P 3306 -u app -p # même principe pour MySQL (-L 3306:127.0.0.1:3306)

Pour accéder à une machine tierce depuis le serveur : -L 8080:10.0.0.30:80 (le port 80 de 10.0.0.30, vu du serveur).

Le tunnel écoute par défaut sur 127.0.0.1 du poste local : seuls les programmes de ce poste l’utilisent. Éviter -L 0.0.0.0:5432:… qui l’ouvre au réseau local.

Redirection distante (-R) : exposer un service local

Section intitulée « Redirection distante (-R) : exposer un service local »

Rend un port du poste local accessible depuis le serveur :

Fenêtre de terminal
ssh -N -R 9100:127.0.0.1:8000 monserveur

Sur le serveur, curl http://127.0.0.1:9100/ atteint le service qui écoute sur le port 8000 du poste (par exemple pour présenter un site en développement). Par défaut, le port distant n’écoute que sur 127.0.0.1 du serveur.

Pour l’exposer à d’autres machines, activer GatewayPorts clientspecified dans sshd_config (déconseillé sans pare-feu) et utiliser -R 0.0.0.0:9100:127.0.0.1:8000.

Fenêtre de terminal
ssh -N -D 1080 monserveur
curl --socks5-hostname 127.0.0.1:1080 https://exemple.com/

Les navigateurs ou outils configurés avec le proxy SOCKS 127.0.0.1:1080 sortent par le serveur. --socks5-hostname fait aussi résoudre les noms par le serveur.

Atteindre une machine qui n’est joignable que par un serveur intermédiaire (« bastion ») :

Fenêtre de terminal
ssh -J monserveur deploy@10.0.0.20
ssh -J bastion1,bastion2 deploy@10.0.0.20 # plusieurs rebonds
scp -J monserveur fichier deploy@10.0.0.20:/tmp/

Dans ~/.ssh/config :

Host interne
HostName 10.0.0.20
User deploy
ProxyJump monserveur

Les données restent chiffrées de bout en bout entre le poste et la machine finale : le bastion ne voit pas le contenu. La clé privée reste sur le poste (contrairement à ssh -A, à éviter).

Option Rôle
-N Pas de commande distante
-f Arrière-plan (après authentification)
-o ExitOnForwardFailure=yes Quitte si le tunnel ne peut pas être établi (indispensable dans un script)
-o ServerAliveInterval=30 Maintient et détecte la coupure du tunnel
-g Autorise d’autres machines à utiliser un tunnel -L local (prudence)
Fenêtre de terminal
ssh -f -N -o ExitOnForwardFailure=yes -o ServerAliveInterval=30 -L 5432:127.0.0.1:5432 monserveur

Arrêter un tunnel en arrière-plan :

Fenêtre de terminal
pgrep -af "ssh -f -N" # repérer le processus
pkill -f "ssh -f -N -o ExitOnForwardFailure=yes"

Un service systemd relance le tunnel automatiquement s’il tombe (voir systemd : services). Fichier /etc/systemd/system/tunnel-bdd.service sur le poste (ou la machine qui doit toujours avoir le tunnel) :

[Unit]
Description=Tunnel SSH vers la base de données
After=network-online.target
Wants=network-online.target
[Service]
User=deploy
ExecStart=/usr/bin/ssh -NT -o ExitOnForwardFailure=yes -o ServerAliveInterval=30 -o ServerAliveCountMax=3 -o StrictHostKeyChecking=yes -L 5432:127.0.0.1:5432 monserveur
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
Fenêtre de terminal
sudo systemctl daemon-reload
sudo systemctl enable --now tunnel-bdd
systemctl status tunnel-bdd

Le compte deploy doit disposer de la clé (sans phrase secrète, ou via un agent) et du serveur dans known_hosts. Pour cette clé de tunnel, limiter ses droits côté serveur (restrict,port-forwarding,permitopen="127.0.0.1:5432" dans authorized_keys).

Dans authorized_keys du serveur, une clé destinée à un seul tunnel :

restrict,port-forwarding,permitopen="127.0.0.1:5432" ssh-ed25519 AAAAC3Nza… tunnel-bdd

restrict retire tous les droits, port-forwarding rend les redirections possibles, et permitopen les limite à la destination indiquée.

Symptôme Piste
bind [127.0.0.1]:5432: Address already in use Le port local est déjà utilisé : un autre tunnel, ou PostgreSQL local. Changer le port local (-L 15432:127.0.0.1:5432)
channel 2: open failed: connect failed: Connection refused Rien n’écoute à la destination vue du serveur (mauvais port ou adresse)
administratively prohibited: open failed AllowTcpForwarding no sur le serveur, ou permitopen qui ne l’autorise pas
Le tunnel se coupe après un moment Ajouter ServerAliveInterval ; utiliser le service systemd ci-dessus
Warning: remote port forwarding failed for listen port Port distant déjà pris, ou -R interdit
Le tunnel marche mais l’application ne se connecte pas Utiliser 127.0.0.1 (et non localhost, qui peut résoudre en IPv6)