Enregistrez chaque tunnel dans ~/.ssh/config
Retaper les options -L et -R à chaque fois, c'est la meilleure façon de mélanger les ports. Donnez plutôt un nom à chaque tunnel, dans son propre bloc Host :
Host db-tunnel
HostName 203.0.113.10
User deploy
LocalForward 127.0.0.1:5432 127.0.0.1:5432
ExitOnForwardFailure yes
Host dev-share
HostName 203.0.113.10
User deploy
RemoteForward 127.0.0.1:9000 127.0.0.1:3000
Host socks
HostName 203.0.113.10
User deploy
DynamicForward 127.0.0.1:1080
Chaque ligne est la forme « configuration » d'une option de ligne de commande : LocalForward correspond à -L, RemoteForward à -R et DynamicForward à -D. L'adresse et le port d'écoute viennent d'abord, puis un espace, puis la destination. Comme avec les options, c'est le serveur qui résout la destination d'une redirection locale : 127.0.0.1 y désigne donc le serveur lui-même. Si ces trois types sont nouveaux pour vous, commencez par les tunnels SSH local, distant et dynamique expliqués.
Utilisez un nom à part pour les tunnels, pas le Host avec lequel vous vous connectez tous les jours. Sinon chaque connexion tente d'ouvrir les mêmes ports, et la deuxième affiche Address already in use.
Lancez un tunnel par son nom
ssh -f -N db-tunnel
-N n'exécute aucune commande distante : la connexion ne transporte que les redirections. -f envoie ssh en arrière-plan après la connexion, si bien que la demande de phrase de passe ou de mot de passe vous parvient d'abord. Votre outil de base de données peut maintenant se connecter à 127.0.0.1:5432.
Avec ExitOnForwardFailure yes, un port déjà pris arrête ssh avec le code de sortie 255 au lieu de laisser une connexion sans tunnel. Voici ce que donne le lancement du même tunnel une seconde fois :
bind [127.0.0.1]:5432: Address already in use
channel_setup_fwd_listener_tcpip: cannot listen to port: 5432
Could not request local forwarding.
Pour lancer plusieurs tunnels enregistrés d'un coup :
for t in db-tunnel socks; do ssh -f -N "$t"; done
Arrêtez un tunnel
Un tunnel en arrière-plan n'est qu'un processus ssh. Sans rien d'autre, on le retrouve et on le tue :
ps ax | grep '[s]sh -f -N db-tunnel'
pkill -f 'ssh -f -N db-tunnel'
pkill -f vise tout processus dont la ligne de commande contient ce texte. Dans nos tests, il a aussi tué le script shell qui avait lancé le tunnel, parce que le script contenait les mêmes mots. Un socket de contrôle est plus propre. Ajoutez trois lignes au bloc :
Host db-tunnel
HostName 203.0.113.10
User deploy
LocalForward 127.0.0.1:5432 127.0.0.1:5432
ExitOnForwardFailure yes
ControlMaster auto
ControlPath ~/.ssh/cm-%C
ControlPersist yes
Le tunnel répond désormais aux commandes par son nom :
ssh -f -N db-tunnel
ssh -O check db-tunnel
ssh -O exit db-tunnel
Master running (pid=27)
Exit request sent.
Le socket permet aussi aux autres commandes ssh et scp vers db-tunnel de réutiliser la même connexion. Les détails sont dans le multiplexage SSH avec ControlMaster.
Ajoutez ou retirez une redirection sans vous reconnecter
Avec un socket de contrôle, vous pouvez modifier un tunnel en cours. La connexion et ses autres redirections restent actives :
ssh -O forward -L 127.0.0.1:8081:127.0.0.1:8000 db-tunnel
ssh -O cancel -L 127.0.0.1:8081:127.0.0.1:8000 db-tunnel
cancel exige exactement la même spécification que celle utilisée pour ajouter la redirection. Cela fonctionne aussi pour -R et -D. Avec -R 0:..., le serveur choisit un port libre et ssh -O forward l'affiche.
Gardez un tunnel enregistré actif
Un tunnel lancé avec -f vit aussi longtemps que sa connexion SSH. Une mise en veille, un changement de Wi-Fi ou un redémarrage du serveur y met fin. Ajoutez ces lignes au bloc pour que ssh repère une connexion morte en 45 secondes environ et se termine, au lieu de rester bloqué :
ServerAliveInterval 15
ServerAliveCountMax 3
Il faut ensuite quelque chose pour le relancer : une boucle, un gestionnaire de services ou autossh pour un tunnel SSH persistant.
Les erreurs qui cassent les tunnels enregistrés
- Deux-points au lieu d'un espace.
LocalForward 5432:127.0.0.1:5432est le format de la ligne de commande, pas celui de la configuration. ssh répondMissing target argument, et dans notre test cette seule ligne fautive a empêché tous les hôtes du fichier de se connecter. - Écoute sur toutes les interfaces.
LocalForward 0.0.0.0:5432 ...ouGatewayPorts yespermettent à d'autres machines de votre réseau d'utiliser le tunnel. Gardez127.0.0.1, sauf si c'est voulu. - Deux tunnels sur le même port local. Seul le premier démarre. Donnez à chaque tunnel enregistré son propre port.
- Redirection refusée par le serveur. Si le port s'ouvre mais que les connexions échouent avec
administratively prohibited, le serveur a désactivéAllowTcpForwardingpour vous.
Questions
Comment voir quels tunnels SSH sont actifs ?
Lancez ps ax | grep '[s]sh -f -N' pour lister les processus ssh en arrière-plan avec leurs options. Pour un tunnel avec socket de contrôle, ssh -O check nom répond directement. Dans une session interactive, appuyez sur Entrée puis tapez ~# pour lister les connexions redirigées.
Une seule commande peut-elle lancer plusieurs tunnels ?
Oui. Placez plusieurs lignes LocalForward ou DynamicForward dans un même bloc Host : elles s'ouvrent toutes avec un seul ssh -f -N nom. Si un port est occupé et que ExitOnForwardFailure est activé, aucune ne reste ouverte.
Pourquoi mon tunnel enregistré s'arrête-t-il après une mise en veille ou un changement de réseau ?
Le tunnel vit dans une seule connexion SSH, qui meurt quand le réseau tombe. Ajoutez ServerAliveInterval pour que ssh s'en aperçoive, et relancez-le avec une boucle ou avec autossh.
Sources
- ssh(1), -f, -N et -O, manuel OpenBSD
- ssh_config(5), LocalForward, RemoteForward, DynamicForward, ControlMaster
- sshd_config(5), AllowTcpForwarding et GatewayPorts