2つのSSHポート転送を連鎖する

2つのSSHポート転送を連鎖する

私はここでスーパーユーザーの回答を閲覧してきましたが、私のユースケースに対応する回答は見つかりませんでした。

トンネルを通過できる 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:10001Aからの接続を許可しない、
  • あるいは何でも。

ssh … && ssh …

2 番目のコマンドは、最初の接続から「終了」した後にのみ実行されます。

はい、これは正常です。次のコマンドが実行される前に、前の部分が&&終了し、終了ステータスを返す必要があります (ステータスによっては実行されない場合もあります)。

これは 2 番目をsshほぼ即座に実行しますが、欠陥があります。

( ssh … & ) && ssh …

最初のものはssh2 番目のものに影響を与えないので、欠陥があります。2 番目のものは、最初のものがトンネルを確立するずっと前に実行される可能性があります。パスワードを要求することも問題になる可能性があります。

この使用例にはオプションsshがあります-fman 1 ssh:

-f
sshコマンド実行の直前にバックグラウンドに移行するように 要求します。[…]

したがって、基本的なコマンドは次のようになります。

ssh -fNL 22:hostB:22 user@hostA && ssh -NL 10002:localhost:10001 user@localhost

-N2 番目を使用するかどうかは、あなた次第です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 exitssh
  • 最初のソケットsshが突然終了した場合、ソケットはそのまま残ります。これにより、新しい最初のsshソケットは失敗します。0 番目のソケットを次のように拡張すると良いでしょうssh

    ssh -S "$socket" -O exit dummy || rm "$socket"
    
  • /tmp/hostA.socketソケットに最適な場所ではないかもしれません。コマンドラインオプションssh_configに相当するのは です。-SControlPathman 5 ssh_configそれについてこう述べています。

    ControlPath便宜的接続共有に使用する には、少なくとも%h%p%r(または代わりに%C) を含め、他のユーザーが書き込みできないディレクトリに配置することをお勧めします。

    「他のユーザーが書き込みできないディレクトリ」は、OS がサポートしている場合、 である可能性があります(の機能だ/run/user/$UIDと思います)。systemd

関連情報