一時的なSSHトンネルを設定するBashスクリプト


132

Cygwinでは、Bashスクリプトで以下を実行します。

  1. リモートサーバーへのSSHトンネルを作成します。
  2. トンネルを使用するローカルでいくつかの作業を行います。
  3. 次に、トンネルをシャットダウンします。

シャットダウン部分は困惑しています。

現在、私は不十分な解決策を持っています。1つのシェルで次のコマンドを実行してトンネルを作成します。

# Create the tunnel - this works! It runs forever, until the shell is quit.
ssh -nNT -L 50000:localhost:3306 jm@sampledomain.com

次に、別のシェルウィンドウで作業を行います。

# Do some MySQL stuff over local port 50000 (which goes to remote port 3306)

最後に、完了したら、最初のシェルウィンドウを閉じてトンネルを終了します。

これを次のような1つのスクリプトで実行したいと思います。

# Create tunnel
# Do work
# Kill tunnel

どのようにしてトンネルプロセスを追跡すれば、どのプロセスを強制終了すればよいかわかりますか?


:私は、SSHトンネリングを行うために役立つだろう、スクリプトを書いて、あなたはでそれをチェックアウトすることができgithub.com/gdbtek/ssh-tunneling.git
ナム・グエン

回答:


324

これは、sshの「制御ソケット」を使用して問題なく実行できます。すでに実行中のSSHプロセスと通信してpidを取得するには、プロセスを強制終了します。次のように、「制御ソケット」(マスターの場合は-M、ソケットの場合は-S)を使用します。

$ ssh -M -S my-ctrl-socket -fnNT -L 50000:localhost:3306 jm@sampledomain.com
$ ssh -S my-ctrl-socket -O check jm@sampledomain.com
Master running (pid=3517) 
$ ssh -S my-ctrl-socket -O exit jm@sampledomain.com
Exit request sent. 

my-ctrl-socketが実際に作成されるファイルになることに注意してください。

私はOpenSSHメーリングリストの非常にRTFMの返信からこの情報を得ました


6
これは、これまでこのトピックで見た中で最良の答えです。誠にありがとうございました。これを使用してVagrant VMに接続し、FlywayDB更新スクリプトを実行します。
クリスチャン

2
どうやら制御ソケットはどこでも機能しない。例えば、私が手Operation not permitteddrone.io継続的インテグレーション環境で:muxserver_listen: link mux listener ssh-ctrl-socket.wsASkszgSBlK7kqD => ssh-ctrl-socket: Operation not permitted
ミッコOhtamaa

my-ctrl-socketこれを実行すると、ファイルはどうなりますか?ls -la現在のフォルダーで行うと、ファイルが表示されなくなります。
サチンク

2
スクリプトで使用する場合は、制御ソケットが使用可能になるまで数秒間待つ必要があります。私の解決策:while [ ! -e $ctrl_socket ]; do sleep 0.1; done
Adam Wallner、2018

私がこれを行ったとき、私はそれを手open failed: administratively prohibited: open failedに入れていますが、それがトンネルを開いているとは思いません
Andy Ray

21

-fオプションを使用すると、SSHにバックグラウンド自体を通知できますが、$!を使用してPIDを取得することはできません。また、トンネルを使用する前にスクリプトを任意の時間スリープさせるのではなく、-o ExitOnForwardFailure = yesを-fとともに使用すると、SSHはすべてのリモートポート転送が正常に確立されるのを待ってから、バックグラウンドに配置します。psの出力をgrepしてPIDを取得できます。例えばあなたは使うことができます

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

そして、あなたが望ましいPIDを取得していることをかなり確認してください


気付かないかもしれませんが、これは一種の天才です。私はSSHトンネルPIDを追跡する方法を探していましたが、ほとんどsystemdサービススクリプトを使用してしまいました。もうありません:トンネル名を使用して、必要なSSHプロセスをgrepできます。このアイデアはどういうわけか私を完全にスキップしました。どうもありがとう!
-aexl

19
  • コマンドラインフラグを使用して、反対側にシェルを作成せずに(トンネルを開くだけで)sshバックグラウンドに入るように指示することができます&(これは、-N)。
  • PIDを保存 PID=$!
  • あなたのことをしてください
  • kill $PID

編集:$を修正しましたか?$!&を追加しました


3
スクリプトがKILLに到達する前にどこかで停止した場合、その処理に注意する必要があります。
jm。

2
@jm:trap 'kill $PID' 1 2 15スクリプト失敗の多くのケースをカバーします。
ノーマンラムジー

3
これが確実に機能するためには、トンネルを作成した後、それを使用する前に少し「スリープ」する必要がありました。
jm。

@NormanRamseyつまりtrap "kill $PID"、bashは二重引用符で囲まれた文字列内の変数のみを補間するためです
JuanCaicedo

1
@JuanCaicedoこの区別は、PID変数が後で再定義された場合にのみ重要になります。変数は、trap組み込みが呼び出されたとき(OPのアプローチ)またはシグナルがキャッチされたとき(ユーザーのアプローチ)に展開されます。ここでは両方のアプローチで同じ結果が得られます。
Witiko

4

個別のタスクのために新しいシェルを起動することを好み、次のコマンドの組み合わせをよく使用します。

  $ sudo bash; exit

または時々:

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

これらのコマンドは、すべての作業を実行できる入れ子のシェルを作成します。終了したらCTRL-Dを押すと、親シェルもクリーンアップして終了します。ネストされたシェルからログアウトするとトンネルが閉じられるようbash;に、killパーツの直前にsshトンネルスクリプトを簡単に投入できます。

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

とても興味深い。これにより、「トラップ」問題をより適切に処理できます。それを試さなければならないでしょう。
jm。

2

エンドsshをaで起動して&、バックグラウンドに配置し、実行時にIDを取得できます。その後、kill完了したらそのIDを実行する必要があります。


アンパサンド( "&")を使用する場合は注意してください。自分のために確立された実際の接続を決定する必要があるため、これは醜いアプローチです。実際の接続が完全に確立されるのを待っていないコードが実行される可能性があります。さらに、スクリプトが壊れても接続は自動的に終了しません。
ジョナサン

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.