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

ssh tunnel

SSHでのデータのトンネリングは非常に簡単です

ssh -D9999 username@example.com

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

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

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

  389  Mala  2010-01-16


ベストアンサー

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

  1. localhostからhost1へのトンネル

    ssh -L 9999:host2:1234 -N host1
    

    前述の通り、host1からhost2への接続は確保されません

  2. localhostからhost1へ、host1からhost2へのトンネル

    ssh -L 9999:localhost:9999 host1 ssh -L 9999:localhost:1234 -N host2
    

    これにより、localhostからhost1までのトンネルと、host1からhost2までの別のトンネルが開かれます。しかし、ポート 9999 から host2:1234host1 の誰でも使うことができます。これは問題になるかもしれないし、ならないかもしれない

  3. localhostからhost1へ、localhostからhost2へのトンネル

    ssh -L 9998:host2:22 -N host1
    ssh -L 9999:localhost:1234 -N -p 9998 localhost
    

    これにより、localhost から host1 へのトンネルが開かれ、host2 の SSH サービスが利用できるようになります。そして、最初のトンネルを通って localhost から host2 に 2 つ目のトンネルが開かれます

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

368  Mika Fischer  2010-01-17


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

165  kynan  2010-08-01


OpenSSH v7.3 以降では -J スイッチと ProxyJump オプションがサポートされています

ssh -J jumpuser1@jumphost1,jumpuser2@jumphost2,...,jumpuserN@jumphostN user@host

48  nikolay  2016-08-10


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

この手順を自動化するには、以下のスクリプトを使用します

#!/bin/bash
ssh -f -L some_port:private_machine:22 user@gateway "sleep 10" && ssh -p some_port private_user@localhost

何が起きているのか

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

20  Bernhard Kausler  2010-01-24


上記を読んで全てを接着した後、以下の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($_);
}

Usage:

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

18  Bob Muller  2012-01-11


この答えは、ProxyCommandの使用を伴うので、kynanと似ています。しかし、IMOではその方が便利です

ホップマシンに netcat がインストールされている場合は、このスニペットを ~/.ssh/config に追加することができます

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

Then

ssh -D9999 host1+host2 -l username

はあなたの頼みを聞いてくれます

このトリックを読んだ元の場所を探してここに来ました。見つけたらリンクを貼っておきますね

8  silviot  2013-03-13


思うようなことをしました

ssh -D 9999 -J host1 host2

両方のパスワードの入力を求められたので、host2へのSOCKSプロキシとしてlocalhost:9999を使うことができます。これが最初に示した例に最も近いと思います

7  Cheryl  2017-11-21


私の回答は、ここの他の回答と本当に同じなのですが、~/.ssh/configとProxyJumpの有用性を明確にしたかったのです

例えば、3ホップで目的地に到達する必要があり、各ホップごとに特定のユーザ名、ホスト、ポート、IDが必要だとします。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

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

[yourpc] $ ssh hop1 # will go from your PC to host1 in a single step
[host1] $ exit
[yourpc] $ ssh hop2 # will go from your PC to host2 via host1 (i.e. two steps)
[host2] $ exit
[yourpc] $ ssh hop3 # will go from your PC to host3 via host1 and host2 (i.e. three steps)
[host3] $ exit
[yourpc] $

~/.ssh/config ファイルについてのもう一つのクールな点は、これによって sftp ファイルの転送も可能になるということです

[yourpc] $ sftp hop1 # for file transfers between your PC and host1
Connected to hop1.
sftp> quit
[yourpc] $ sftp hop2 # for file transfers between your PC and host2
Connected to hop2.
sftp> quit
[yourpc] $ sftp hop3 # for file transfers between your PC and host3
Connected to hop3.
sftp> quit

5  Stephen Quan  2019-12-18


ssh -L 9999:host2:80 -R 9999:localhost:9999 host1

-L 9999:host2:80

つまり、localhost:9999にバインドして、localhost:9999に送られたパケットをhost2:80に転送する

-R 9999:localhost:9999

host1:9999で受信したパケットをlocalhost:9999に転送することを意味します

4  chinmaya  2010-01-19


を使うと、ポートフォワーディングを使って host2 のサービスに localhost からアクセスできるようになるはずです。良いガイドは こちら にあります。抜粋

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

例えば、コマンドを発行すると

ssh2 -L 1234:localhost:23 username@host

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

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

例えば、コマンドを発行すると

ssh2 -R 1234:localhost:23 username@host

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

キャストでは、例のlocalhosthost2に、hosthost1に置き換えてください

2  fideli  2010-01-16


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

Problem statement

以下のようなネットワークトポロジーを想定してみましょう

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

具体的には、以下のコンピュータのホスト名、ユーザ名、パスワードがあるとします

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

目標: LocalPC のポート 9991 をリッスンする SOCKS プロキシを設定して、LocalPC の接続がポート 9991 から開始されるたびに mit.edu を通過し、hec.edu を通過するようにしたい

使用例。hec.edu には、セキュリティ上の理由から http://127.0.0.1:8001 にしかアクセスできない HTTP サーバがあります。LocalPCでWebブラウザを開いてhttp://127.0.0.1:8001にアクセスできるようにしたい


Configuration

LocalPCでは、~/.ssh/configで追加します

Host HEC
HostName hec.edu
User john
ProxyCommand ssh bob@mit.edu -W %h:%p

そして、LocalPCのターミナルで実行します

ssh -D9991 HEC

bobのパスワードをmit.edu(つまりdylan123)で聞き、johnのパスワードをhec.edu(つまりdoe456)で聞きます

その時点で、SOCKSプロキシはLocalPC9991ポートで動作するようになりました

例えば、SOCKSプロキシを使ってLocalPCのウェブページにアクセスしたい場合は、Firefoxで行うことができます

enter image description here

Some remarks:

  • ~/.ssh/config, HEC は接続名です
  • -D9991は、sshにポート9991にSOCKS4プロキシを設定するよう指示します

2  Franck Dernoncourt  2017-03-18


もし両方のマシンに SSH 接続できるのであれば、ssh の ProxyCommand ディレクティブを見てください。これを使うと、localhost から host2 に直接入ることができます (公開鍵を使うのであれば、一回のコマンドで簡単にできます!)。そうすれば、host2 でやりたいことが何でもできるようになります

SSH ProxyCommand | Status-Q
Quentin Stafford-Fraser's blog

0  None  2010-01-19


ベストアンサーのオプション2は、現在のものとは異なるsshユーザで使用することができます

    export local_host_port=30000
export host1_user=xyz
export host1=mac-host
export host1_port=30000
export host2=192.168.56.115
export host2_user=ysg
export host2_port=13306

# Tunnel from localhost to host1 and from host1 to host2
# you could chain those as well to host3 ... hostn
ssh -tt -L $local_host_port:localhost:$host1_port $host1_user@$host1 \
ssh -tt -L $host1_port:localhost:$host2_port $host2_user@$host2

0  Yordan Georgiev  2017-10-05


私の場合は

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

ここで、host2:8890はJupyter Notebook上で動作しています

そして、FirefoxをSOCKSホストとしてlocalhost:9999を使うように設定してみました

ということで、今では私のマシンのhost2でノートPCを起動し、localhost:8890でFirefoxからアクセスできるようになりました

0  amarion  2018-07-26


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

本番サーバに直接sshすることができず、ジャンプサーバを使って1ホップしなければなりません

Yet Another Solution – ナイーブなもの

結局、私は非常にナイーブな方法でそれを行うことになりました: 私のラップトップ上ですべてのコマンドを実行しようとする代わりに、私は以下のように、それぞれのマシン上でコマンドを実行しています

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

いくつかのメッセージを印刷した後に、”hanggs “というコマンドが表示されているのを見るべきです。一つの例外 – Could not request local forwarding. のようなエラーメッセージは表示されないはずですが、もし表示された場合はまだ動作していません。ラップトップからポート6969でリクエストを実行してみて、動作するかどうか確認してみてください

うまくいけば、あなたが上記のすべての方法に失敗した人であれば、おそらくあなたはこれを試すことができます

0  Shaung Cheng  2019-08-20


これだけは、二人以上のホストに助けられた

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

3つのパスワードを入力します

この回答に触発されて

0  Vladimir Iashin  2020-02-22


タイトルとURLをコピーしました