私はここでスーパーユーザーの回答を閲覧してきましたが、私のユースケースに対応する回答は見つかりませんでした。
トンネルを通過できる 2 つのコマンドを連結したいと思います。
ssh -L 22:hostB:22 user@hostA
そして
ssh -L 10002:localhost:10001 user@localhost
今私がやっていることは、最初のコマンドを入力し、別のターミナルを開いて、2番目のコマンドを入力することです。
ssh … && ssh …
2 番目のコマンドは、最初の接続から「終了」した後にのみ実行されます。
jumphost のようなより高度な ssh オプションは、hostA のサーバー構成により機能しないため、これが 10001 ポートをこのようにアクセス可能にする唯一のオプションであると確信しています。
これら 2 つのコマンドを 1 つのエイリアスに連結したり、タイムアウトなどの簡単な bash スクリプトを使用したりする方法はありますか?
答え1
なぜならssh -L 10002:hostB:10001 user@hostA
、
- Bでリッスンするものは
10001
ローカルインターフェースのみにバインドするか、 - または、Bのファイアウォールが
hostB:10001
Aからの接続を許可しない、 - あるいは何でも。
ssh … && ssh …
2 番目のコマンドは、最初の接続から「終了」した後にのみ実行されます。
はい、これは正常です。次のコマンドが実行される前に、前の部分が&&
終了し、終了ステータスを返す必要があります (ステータスによっては実行されない場合もあります)。
これは 2 番目をssh
ほぼ即座に実行しますが、欠陥があります。
( ssh … & ) && ssh …
最初のものはssh
2 番目のものに影響を与えないので、欠陥があります。2 番目のものは、最初のものがトンネルを確立するずっと前に実行される可能性があります。パスワードを要求することも問題になる可能性があります。
この使用例にはオプションssh
があります-f
。man 1 ssh
:
-f
ssh
コマンド実行の直前にバックグラウンドに移行するように 要求します。[…]
したがって、基本的なコマンドは次のようになります。
ssh -fNL 22:hostB:22 user@hostA && ssh -NL 10002:localhost:10001 user@localhost
-N
2 番目を使用するかどうかは、あなた次第ですssh
。ここでの秘訣は、最初のプロセスssh
が、パスワードを要求した後 (該当する場合)、および最初のトンネルを確立した後、バックグラウンドにフォークすることです。そのため、一時的に 2 つの「最初の」プロセスが存在しますssh
。バックグラウンドのプロセスがトンネルの処理を開始し、フォアグラウンドのプロセスが終了して、&&
作業が可能になります。
おそらく が必要です-o ExitOnForwardFailure=yes
。最初のトンネルを確立できない場合、最初のトンネルssh
は失敗して終了し、2 番目のトンネルは実行されません。改善されたコマンドは次のとおりです。
ssh -fNL 22:hostB:22 \
-o ExitOnForwardFailure=yes \
user@hostA &&
ssh -NL 10002:localhost:10001 user@localhost
2 番目のssh
プロセスが終了した場合、最初のプロセス (バックグラウンド) は残ります。利点は、2 番目のプロセスをssh
後で実行できることです。欠点は、最初のプロセスを残したくない場合は手動で終了する必要があることです。これを念頭に置いて、次のアプローチを検討してください。
ssh -fNL 22:hostB:22 \
-o ExitOnForwardFailure=yes \
user@hostA
ssh -NL 10002:localhost:10001 user@localhost
がないことに注意してください&&
。古い最初のトンネルがssh
まだ実行されている場合、新しいトンネルはポートにバインドできないため失敗します。2 番目のトンネルはssh
関係なく実行され、最初のトンネルを使用し、トンネルがどれだけ古いかは関係ありません。
古いものがなくssh
、最初のものssh
が何らかの理由で失敗することがあります。その場合、2 番目のものが実行され、ポートでリッスンしているものがないため、おそらく失敗します (接続が拒否されます) 22
。
それでも、「アイドル」プロセスをそのままにしたくない場合はssh
、2 番目のプロセスssh
が終了した後に自動的に終了させたい場合があります。明らかに、killall ssh
付随的な損害が発生する可能性があります。もっと微妙な方法を見つけましょう。
-M
ssh
接続共有のためにクライアントを「マスター」モードに します。[…][…]
-O ctl_cmd
アクティブな接続多重化マスタープロセスを制御します。[…][…]
-S ctl_path
接続共有用の制御ソケットの場所を指定します […]
#!/bin/sh
socket=/tmp/hostA.socket
ssh -fNL 22:hostB:22 \
-o ExitOnForwardFailure=yes \
-MS "$socket"
user@hostA &&
{
ssh -NL 10002:localhost:10001 user@localhost
ssh -S "$socket" -O exit dummy
}
2 番目のコマンドが終了した後ssh
、3 番目のコマンドは最初のコマンドに終了を指示します。3 番目のssh
コマンドでは、ホスト名ではなくソケットが重要です。それでも、何らかのホスト名を提供する必要がありますdummy
。最初のssh
コマンドは終了前にソケットを削除するので、ゴミは残らないはずです。
まだいくつか懸念事項があります:
- スクリプトが中断された場合、最初のスクリプト
ssh
が残ります。念のため、ドロップする&&
か、先頭に送信してください(0 番目になります)。-O exit
ssh
最初のソケット
ssh
が突然終了した場合、ソケットはそのまま残ります。これにより、新しい最初のssh
ソケットは失敗します。0 番目のソケットを次のように拡張すると良いでしょうssh
。ssh -S "$socket" -O exit dummy || rm "$socket"
/tmp/hostA.socket
ソケットに最適な場所ではないかもしれません。コマンドラインオプションssh_config
に相当するのは です。-S
ControlPath
man 5 ssh_config
それについてこう述べています。ControlPath
便宜的接続共有に使用する には、少なくとも%h
、%p
、%r
(または代わりに%C
) を含め、他のユーザーが書き込みできないディレクトリに配置することをお勧めします。「他のユーザーが書き込みできないディレクトリ」は、OS がサポートしている場合、 である可能性があります(の機能だ
/run/user/$UID
と思います)。systemd