144 votes

Script Bash pour mettre en place un tunnel SSH temporaire

Sous Cygwin, je veux un script Bash pour :

  1. Créer un tunnel SSH vers un serveur distant.
  2. Faire du travail localement qui utilise le tunnel.
  3. Puis fermer le tunnel.

La partie de fermeture me laisse perplexe.

Actuellement, j'ai une solution bancale. Dans un shell, j'exécute ce qui suit pour créer un tunnel :

# Créer le tunnel - cela fonctionne ! Il s'exécute à l'infini, jusqu'à ce que le shell soit quitté.
ssh -nNT -L 50000:localhost:3306 jm@sampledomain.com

Ensuite, dans une autre fenêtre de shell, je fais mon travail :

# Faire des trucs MySQL sur le port local 50000 (qui va vers le port distant 3306)

Enfin, lorsque j'ai fini, je ferme la première fenêtre du shell pour tuer le tunnel.

J'aimerais faire tout cela dans un seul script comme :

# Créer le tunnel
# Faire le travail
# Tuer le tunnel

Comment puis-je suivre le processus du tunnel, afin de savoir lequel tuer ?

0 votes

J'ai écrit un script qui vous aiderait à faire du tunneling ssh, vous pouvez le consulter sur: github.com/gdbtek/ssh-tunneling.git

357voto

Chris McCormick Points 356

Vous pouvez le faire proprement avec un 'control socket' ssh. Pour communiquer avec un processus SSH déjà en cours d'exécution et obtenir son pid, le tuer, etc. Utilisez le 'control socket' (-M pour maître et -S pour socket) comme suit:

$ ssh -M -S my-ctrl-socket -fNT -L 50000:localhost:3306 jm@sampledomain.com
$ ssh -S my-ctrl-socket -O check jm@sampledomain.com
Maître en cours d'exécution (pid=3517) 
$ ssh -S my-ctrl-socket -O exit jm@sampledomain.com
Demande de sortie envoyée. 

Notez que my-ctrl-socket sera un fichier réel qui est créé.

J'ai obtenu ces informations d'une réponse très RTFM sur la liste de diffusion OpenSSH.

9 votes

Ceci est la meilleure réponse que j'ai vue sur le sujet jusqu'à présent. Merci beaucoup, elle devrait être acceptée. Je l'utilise pour me connecter à ma machine virtuelle Vagrant et exécuter un script de mise à jour FlywayDB.

2 votes

Apparemment, les sockets de contrôle ne fonctionnent pas partout. Par exemple, j'obtiens Operation not permitted sur l'environnement d'intégration continue de drone.io : muxserver_listen: link mux listener ssh-ctrl-socket.wsASkszgSBlK7kqD => ssh-ctrl-socket: Operation not permitted

0 votes

Donc que se passe-t-il avec le fichier my-ctrl-socket après cela? Quand je fais ls -la dans le dossier actuel, je ne peux plus voir le fichier.

22voto

Maine Guy Points 71

Vous pouvez demander à SSH de se mettre en arrière-plan avec l'option -f mais vous n'obtiendrez pas le PID avec $!. De plus, au lieu de faire dormir votre script pendant un laps de temps arbitraire avant d'utiliser le tunnel, vous pouvez utiliser -o ExitOnForwardFailure=yes avec -f et SSH attendra que tous les port forwards distants soient établis avec succès avant de se placer en arrière-plan. Vous pouvez utiliser grep sur la sortie de ps pour obtenir le PID. Par exemple, vous pouvez utiliser

...
ssh -Cfo ExitOnForwardFailure=yes -N -L 9999:localhost:5900 $REMOTE_HOST
PID=$(pgrep -f 'N -L 9999:')
[ "$PID" ] || exit 1
...

et être assez sûr d'obtenir le PID désiré

0 votes

Vous ne le réalisez peut-être pas, mais c'est un peu génial. Je cherchais un moyen de suivre les PID du tunnel SSH et j'ai failli utiliser les scripts de service systemd. Plus maintenant : je peux retrouver le processus SSH dont j'ai besoin en utilisant le nom du tunnel. Cette idée m'a complètement échappé. Merci beaucoup!

19voto

ZeissS Points 4049
  • Vous pouvez indiquer à ssh d'aller en arrière-plan avec & et de ne pas créer de shell de l'autre côté (juste ouvrir le tunnel) avec un drapeau de ligne de commande (je vois que vous l'avez déjà fait avec -N).
  • Enregistrez le PID avec PID=$!
  • Faites vos choses
  • tuer $PID

EDIT : Corrigé $? à $! et ajouté le &

3 votes

Si mon script meurt quelque part avant d'atteindre le KILL, je dois être prudent pour gérer cela.

2 votes

@jm: trap 'kill $PID' 1 2 15 couvrira de nombreux cas d'échec de script.

3 votes

Pour que cela fonctionne de manière fiable, j'ai dû "dormir" un peu APRÈS avoir créé le tunnel, mais avant de l'utiliser.

4voto

too much php Points 27983

Je préfère lancer un nouveau shell pour des tâches séparées et j'utilise souvent la combinaison de commandes suivante :

  $ sudo bash; exit

ou parfois :

  $ : > sensitive-temporary-data.txt; bash; rm -f sensitive-temporary-data.txt; exit

Ces commandes créent un shell imbriqué où je peux faire tout mon travail ; lorsque j'ai fini, je tape CTRL-D et le shell parent se nettoie et se ferme également. Vous pourriez facilement ajouter bash; dans votre script de tunnel ssh juste avant la partie kill afin que lorsque vous vous déconnectez du shell imbriqué, votre tunnel sera fermé :

#!/bin/bash
ssh -nNT ... &
PID=$!
bash
kill $PID

0 votes

Très intéressant. Cela pourrait mieux résoudre le problème du "piège". Je vais devoir essayer.

2voto

Valentin Rocher Points 7524

Vous pourriez lancer le ssh avec un & à la fin, pour le mettre en arrière-plan et récupérer son id. Ensuite, il vous suffit de faire un kill de cet id quand vous avez terminé.

0 votes

Soyez conscient si vous utilisez l'esperluette ("&"). C'est une approche laide car vous devrez déterminer la véritable connexion établie vous-même. Cela peut entraîner l'exécution de code supplémentaire qui n'attend pas que la connexion réelle soit entièrement établie. De plus, la connexion ne sera pas tuée automatiquement si le script se casse.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X