2010-01-16 05:58:48 +0000 2010-01-16 05:58:48 +0000
354
354

複数のホップを経由したSSHトンネル

SSH上でデータをトンネルするのはかなり簡単です:

ssh -D9999 username@example.com

localhostへのトンネルとしてexample.comのポート9999を設定しますが、私にはもっと具体的なニーズがあります。

  • 私はlocalhost でローカルに作業しています - host1localhost にアクセス可能です - host2host1 からの接続しか受け付けません - 私はlocalhostからhost2へのトンネルを作成する必要があります

事実上、私は “マルチホップ "のSSHトンネルを作成したいと思います。どのようにすればいいのでしょうか?理想的には、マシンのany上でスーパーユーザになる必要なしにこれを行いたいと思います。

回答 (15)

341
341
341
2010-01-17 21:31:56 +0000

基本的には3つの可能性があります:

  1. トンネルは localhost から host1 へ:

    1. localhost から host1 へのトンネル、及び host1 から host2 へのトンネル:
    1. localhost から host1 へのトンネル、及び localhost から host2 へのトンネル:

通常、私はオプション 1 を使用します。host1からhost2への接続を確保する必要がある場合は、オプション2で行きましょう。オプション 3 は、主に host2 自体からしか到達できない host2 上のサービスにアクセスしたい場合に有用である。

158
158
158
2010-08-01 17:10:27 +0000

SSH のための ProxyCommand 設定ディレクティブの使い方を説明した 素晴らしい回答 があります:

これを ~/.ssh/config に追加してください (詳細は man 5 ssh_config を参照してください):

Host host2
  ProxyCommand ssh host1 -W %h:%p

そうすると、ssh host2 は自動的に host1 を通してトンネルを作ります (X11 転送などでも動作します)。

これはドメインで識別されたホストなどのクラス全体に対しても動作します:

Host *.mycompany.com
  ProxyCommand ssh gateway.mycompany.com -W %h:%p

Update

OpenSSH 7.3 は ProxyJump ディレクティブを導入し、最初の例を

Host host2
  ProxyJump host1
``` に単純化しました。
35
35
35
2016-08-10 09:11:34 +0000

OpenSSH v7.3 以降では -J スイッチと ProxyJump オプションをサポートしています。これにより、1つ以上のホストをカンマ区切りでジャンプできるようになります。

20
20
20
2010-01-24 18:47:37 +0000

プライベートネットワークへのsshゲートウェイが1つあります。外部にいて、プライベートネットワーク内のマシンでリモートシェルを使用したい場合は、ゲートウェイに ssh して、そこからプライベートマシンに接続しなければなりません。

この手順を自動化するには、次のスクリプトを使用します。プライベートマシンへの ssh プロトコル (ポート 22) のトンネルを確立します。成功した場合のみ、トンネルを使用してプライベートマシンにsshします。(&&オペレータがこれを保証します) 3. 3. プライベートなsshセッションを閉じた後、sshトンネルも閉じたい。これは “sleep 10” というトリックで行います。通常、最初の ssh コマンドは 10 秒後に終了しますが、その間に 2 番目の ssh コマンドがトンネルを使って接続を確立しています。その結果、最初の ssh コマンドは、次の 2 つの条件が満たされるまでトンネルを開いたままにします: sleep 10 が終了し、トンネルが使用されなくなります。

18
18
18
2012-01-11 11:02:06 +0000

上記を読んで、すべてを一緒に接着した後、私は以下のPerlスクリプトを作成しました(/usr/binにmsshとして保存して実行可能にします):

#!/usr/bin/perl

$iport = 13021;
$first = 1;

foreach (@ARGV) {
  if (/^-/) {
    $args .= " $_";
  }
  elsif (/^((.+)@)?([^:]+):?(\d+)?$/) {
    $user = $1;
    $host = $3;
    $port = $4 || 22;
    if ($first) {
      $cmd = "ssh ${user}${host} -p $port -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no";
      $args = '';
      $first = 0;
    }
    else {
      $cmd .= " -L $iport:$host:$port";
      push @cmds, "$cmd -f sleep 10 $args";
      $cmd = "ssh ${user}localhost -p $iport -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no";
      $args = '';
      $iport ++;
    }
  }
}
push @cmds, "$cmd $args";

foreach (@cmds) {
  print "$_\n";
  system($_);
}

使用法:

HOSTAとHOSTB経由でHOSTCにアクセスするには(同じユーザー)。

mssh HOSTA HOSTB HOSTC

HOSTA と HOSTB 経由で HOSTC にアクセスし、デフォルト以外の SSH ポート番号と異なるユーザを使用するには:

mssh user1@HOSTA:1234 user2@HOSTB:1222 user3@HOSTC:78231

HOSTA と HOSTB 経由で HOSTC にアクセスし、X 転送を使用するには:

mssh HOSTA HOSTB HOSTC -X

HOSTA と HOSTB 経由で HOSTC のポート 8080 にアクセスするには:

mssh HOSTA HOSTB -L8080:HOSTC:8080
8
8
8
2013-03-13 09:57:28 +0000

この答えは、ProxyCommandの使用を伴うので、kynanと似ています。

もしあなたのホップマシンに netcat がインストールされているなら、以下のスニペットを ~/.ssh/config に追加することができます:

Host *+*
    ProxyCommand ssh $(echo %h | sed 's/+[^+]*$//;s/\([^+%%]*\)%%\([^+]*\)$/ -l /;s/:/ -p /') nc $(echo %h | sed 's/^.*+//;/:/!s/$/ %p/;s/:/ /')
ssh -D9999 host1+host2 -l username

はあなたが尋ねたことをしてくれます。見つけたらリンクを貼っておきますね。

6
6
6
2017-11-21 11:06:21 +0000

私はあなたがやりたかったことをthinkしました

ssh -D 9999 -J host1 host2

私は両方のパスワードのためにプロンプトが表示され、私はホスト2へのSOCKSプロキシのためにlocalhost:9999を使用することができます。これは、私が最初の場所で示された例に最も近いと私は考えることができます。

4
4
4
2010-01-19 02:03:35 +0000
ssh -L 9999:host2:80 -R 9999:localhost:9999 host1

-L 9999:host2:80

ローカルホスト:9999にバインドし、ローカルホスト:9999に送信されたパケットをhost2:80

-R 9999:localhost:9999

ホスト1:9999が受信したパケットをローカルホスト:9999に転送することを意味しています。

2
2
2
2010-01-16 06:34:17 +0000

からhost2のサービスにアクセスするためにポートフォワーディングを使うことができるはずです。良いガイドは ここ にあります。抜粋:

ポート転送には、ローカル転送とリモート転送の2種類があります。それぞれ発信トンネル、着信トンネルとも呼ばれています。ローカルポート転送は、ローカルポートに来るトラフィックを指定されたリモートポートに転送します。

例えば、

ssh2 -L 1234:localhost:23 username@host

コマンドを発行すると、クライアント上のポート1234に来るすべてのトラフィックは、サーバ(ホスト)上のポート23に転送されます。接続が確立された後、localhost は sshdserver によって解決されることに注意してください。この場合、localhost はサーバ (ホスト) 自体を指します。

リモートポート転送は、リモートポートに来るトラフィックを指定されたローカルポートに転送します。

例えば、コマンド

ssh2 -R 1234:localhost:23 username@host

サーバ(ホスト)のポート1234に来る全てのトラフィックは、クライアント(localhost)のポート23に転送されます。

キャストでは、例のlocalhostlocalhostに、host2hostに置き換えてください。

1
1
1
2019-12-18 04:08:37 +0000

私の答えは、ここでの他の回答と同じなのですが、~/.ssh/config と ProxyJump の有用性を明確にしたかったのです。ID 基準のため、これは ~/.ssh/config の設定ファイルでしかできません:

Host hop1
    User user1
    HostName host1
    Port 22
    IdentityFile ~/.ssh/pem/identity1.pem

Host hop2
    User user2
    HostName host2
    Port 22
    IdentityFile ~/.ssh/pem/identity2.pem
    ProxyJump hop1

Host hop3
    User user3
    HostName host3
    Port 22
    IdentityFile ~/.ssh/pem/identity3.pem
    ProxyJump hop2

コンピュータからは、それぞれのジャンプを個別にテストすることができます。

1
1
1
2017-03-18 20:13:02 +0000

この回答では、具体的な例を紹介します。コンピュータのホスト名、ユーザ名、パスワードを自分のものに置き換えるだけです。

問題文

次のようなネットワークトポロジーがあるとします:

our local computer <---> server 1 <---> server 2

具体的には、次のようなコンピュータのホスト名、ユーザ名、パスワードがあるとします。目的: ポート9991からLocalPCへの接続が開始されるたびに、LocalPCから9991を経由してmit.eduに接続されるように、hec.eduのポートhec.eduをリッスンするSOCKSプロキシを設定したいと思います。

使用例: LocalPCには、セキュリティ上の理由から、 http://127.0.0.1:8001 でしかアクセスできないHTTPサーバがあります。


設定

LocalPC <---> hostname: mit.edu <---> hec.edu
                          username: bob username: john 
                          password: dylan123 password: doe456

を追加し、LocalPC のターミナルで以下を実行します。のパスワードを聞いてきます。

その時点で、SOCKSプロキシは~/.ssh/configのポートLocalPCで動作していることになります。

例えば、SOCKSプロキシを使ってbobのWebページにアクセスしたい場合、Firefoxで以下のようにすることができます:

いくつかの注意事項:

  • mit.eduでは、dylan123は接続名です: 好きなように変更することができます。
  • johnは、hec.eduにポートdoe456にSOCKS4プロキシを設定するように指示します。
0
0
0
2020-02-22 07:13:01 +0000

これだけが2つ以上のホストで私を助けてくれました:

ssh -L 6010:localhost:6010 user1@host1 \
-t ssh -L 6010:localhost:6010 user2@host2 \
-t ssh -L 6010:localhost:6010 user3@host3

3つのパスワードを入力するように促されます Inspired by this answer

0
0
0
2018-07-26 05:24:38 +0000

私の場合は、

localhost$ ssh -D 9999 host1
host1$ ssh -L 8890:localhost:8890 host2

をして、host2:8890をJupyterノートブック上で実行しています。

その後、Firefoxがlocalhost:9999をSOCKSホストとして使用するように設定しました。

0
0
0
2017-10-05 08:43:30 +0000
0
0
0
2019-08-20 19:09:55 +0000

受け入れられた回答に記載されている3つのオプションは、私のために全く動作しませんでした。私は両方のホストにあまり権限を持っていないので、私たちのDevOpsチームは認証に来るときにかなり厳格なルールを持っているように見えるし、MFAを行っています。

状況は上記の回答と似ていますが、本番サーバに直接sshすることができず、ジャンプサーバを使って1ホップしなければなりません。

  1. 1. ジャンプサーバにSSH接続して、ssh -v -L 6969:localhost:2222 -N your-protected.dest.serverを実行します。パスワードの入力を求められたら、それを入力してください。今度はラップトップで、ssh -v -L 6969:localhost:6969 -N your-jump-server.host.nameを実行してください。これで、ラップトップの6969番ポートでのリクエストがジャンプサーバーに転送されます。それから順番に、私たちは前のステップで設定したので、ジャンプサーバーは再び保護された宛先サーバー上のポート2222にポート6969のリクエストを転送します。

あなたはいくつかのメッセージを印刷した後、そこにコマンドが “ハングアップ "するのが表示されるはずです - それは彼らが働いていることを意味しています! 一つの例外 - Could not request local forwarding. のようなエラーメッセージは表示されないはずですが、もし表示された場合は、まだ動作していません。あなたは今、あなたのラップトップからポート6969にリクエストを発射してみて、それが動作しているかどうかを確認することができます。