web-dev-qa-db-ja.com

複数のホップを経由するSSHトンネル

SSHを介したデータのトンネリングはとても簡単です。

ssh -D9999 [email protected]

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

  • 私はローカルでlocalhostに取り組んでいます
  • Host1localhostにアクセス可能です
  • Host2Host1からの接続のみを受け入れます
  • localhostからHost2へのトンネルを作成する必要があります

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

322
Mala

基本的に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:1234へのポートは、Host1上の誰でも使用できます。これは問題になるかどうかわからない。

  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サービスを使用することができます。それから2番目のトンネルが最初のトンネルを通してlocalhostからHost2へ開かれます。

Host1からHost2への接続を保護する必要がある場合は、通常、オプション2を使用します。オプション3は、Host2からのみアクセス可能なHost2上のサービスにアクセスする場合に便利です。

309
Mika Fischer

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

更新

OpenSSH 7.3では、ProxyJumpディレクティブが導入され、最初の例は次のように単純化されています。

Host host2
  ProxyJump Host1
151
kynan

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

ssh -J jumpuser1@jumphost1,jumpuser2@jumphost2,...,jumpuserN@jumphostN user@Host
21
nikolay

私たちのプライベートネットワークへの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つの条件が満たされるまでトンネルを開いたままにします。スリープ10が終了し、トンネルは使用されなくなります。
21

上記を読み、すべてをまとめてから、次の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
18
Bob Muller

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/:/ /')

それから

ssh -D9999 Host1+Host2 -l username

あなたが尋ねたことをするでしょう。

私はこのトリックを読んだ元の場所を探してここに来ました。見つけたら、リンクを投稿します。

8
silviot
ssh -L 9999:Host2:80 -R 9999:localhost:9999 Host1

-L 9999:ホスト2:80

手段はlocalhost:9999にバインドし、localhost:9999に送信されたパケットはすべてHost2:80に転送します。

-R 9999:ローカルホスト:9999

Host1:9999が受信したパケットがlocalhost:9999に転送されることを意味します。

4
chinmaya

Ithinkあなたがやりたいことをやりました

ssh -D 9999 -J Host1 Host2

両方のパスワードの入力を求められたら、Host2へのSOCKSプロキシにlocalhost:9999を使用できます。それは私があなたが最初に示した例に考えることができる最も近いです。

3
Cheryl

あなたはlocalhostからHost2上のサービスにアクセスするためにポート転送を使うことができるはずです。良いガイドはこちら にあります 。抜粋:

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

たとえば、次のコマンドを発行したとします。

ssh2 -L 1234:localhost:23 username@Host

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

リモートポート転送は逆のことを行います。リモートポートへのトラフィックを指定されたローカルポートに転送します。

たとえば、次のコマンドを発行したとします。

ssh2 -R 1234:localhost:23 username@Host

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

キャストでは、例のlocalhostHost2に、HostHost1に置き換えます。

2
fideli

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

問題文

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

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

具体的にするために、次のコンピュータのホスト名、ユーザー名、およびパスワードがあるとします。

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

目標:LocalPCの接続がポート9991から開始されるたびに9991を経由してmit.eduを経由するように、LocalPCのポートhec.eduで待機するSOCKSプロキシを設定します。

ユースケースの例:hec.eduには、セキュリティ上の理由から http://127.0.0.1:8001 でのみアクセス可能なHTTPサーバーがあります。 LocalPCでウェブブラウザを開いて http://127.0.0.1:8001 にアクセスしたいと思います。


設定

LocalPC~/.ssh/configを追加します。

Host HEC
    HostName hec.edu
    User john
    ProxyCommand ssh [email protected] -W %h:%p

それからLocalPCの端末で、以下を実行してください。

ssh -D9991 HEC

mit.edubobのパスワード(つまりdylan123)を尋ね、次にhec.edujohnのパスワード(つまりdoe456)を尋ねます。

その時点で、SOCKSプロキシはLocalPC9991ポートで実行されています。

たとえば、SOCKSプロキシを使用してLocalPCのWebページにアクセスしたい場合は、Firefoxで次のことができます。

enter image description here

いくつかの発言:

  • ~/.ssh/configでは、HECが接続名です。あなたはそれをあなたが望むものに変更することができます。
  • -D9991は、ポート9991にSOCKS4プロキシを設定するようにsshに指示します。
1

両方のマシンにSSHで接続できる場合は、sshのProxyCommandディレクティブを見てください。これにより、localhostからHost2に直接移動できます(公開鍵を使用している場合は1つの簡単なコマンドで)。それから、あなたはHost2であなたがやりたいことは何でもすることができます。

http://www.statusq.org/archives/2008/07/03/1916/

0
Andrew

受け入れられた回答に記載されている3つのオプションは、私にはまったく機能しませんでした。私は両方のホストに対する権限があまりないので、DevOpsチームは認証に関してMFAを実行する際にかなり厳しいルールを持っているようです。どういうわけか、上記のコマンドは認証ではうまく機能しません。

ただし、コンテキストは上記の回答と本当に似ています。実稼働サーバーに直接sshすることはできず、ジャンプサーバーを使用して1ホップする必要があります。

もう一つの解決策-素朴な解決策

私はラップトップですべてのコマンドを実行しようとする代わりに、次のようにコマンドを実行します各マシンで

  1. ジャンプサーバーに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に再度転送します。

何らかのメッセージを出力した後、コマンドが「ハング」するのが見えるはずです-それは、それらが機能していることを意味します!例外が1つあります。Could not request local forwarding.のようなエラーメッセージが表示されない場合、それでもまだ動作しません:(.

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

0
Shaung Cheng

私の場合は

localhost$ ssh -D 9999 Host1
Host1$ ssh -L 8890:localhost:8890 Host2

Host2:8890はJupyter Notebookで実行されています。

それから私はFirefoxがSOCKSホストとしてlocalhost:9999を使うように設定しました。

それで今私はノートブックを私のマシンのHost2でFirefoxによってアクセス可能なlocalhost:8890上で走らせました。

0
amarion

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

    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