web-dev-qa-db-ja.com

名前ベースの仮想ホストSSHリバースプロキシはありますか?

開発環境でHTTPリバースプロキシが非常に好きになり、DNSベースの仮想ホストリバースプロキシが非常に便利であることがわかりました。ファイアウォールで開いているポートが1つだけ(および標準ポート)あると、管理がはるかに簡単になります。

SSH接続に似たものを見つけたいのですが、あまりうまくいきませんでした。標準以外のポート範囲を開く必要があるため、単純にSSHトンネリングを使用しない方がいいと思います。これを行うことができるものはありますか?

HAProxyはこれを行うことができますか?

37
ahanson

名前ベースのSSHは、プロトコルがどのように機能するかを考えれば可能になるとは思いません。

ここにいくつかの選択肢があります。

  • ゲートウェイとして機能するようにポート22に応答するホストをセットアップすることができます。次に、キーに基づいて要求を内部に転送するようにsshサーバーを構成できます。 SSH Gateway キーを使用した例

  • そのホストをプロキシとして使用するようにクライアントを調整できます。つまり、ゲートウェイホストにSSHで接続し、そのホストを使用して内部ホストに接続します。クライアントのSSHプロキシ 構成

  • Edgeに単純なhttpプロキシをセットアップすることもできます。次に、それを使用して着信接続を許可します。 HTTPプロキシ 経由のSSH。

上記のすべてについて明らかに、ゲートウェイを適切に構成してロックダウンすることは非常に重要です。

24
Zoredache

私はこの問題の解決策を過去16か月間オンとオフで探していました。しかし、私が見るたびに、関連するRFCで指定され、主要な実装によって実装されているSSHプロトコルでこれを行うことは不可能のようです。

ただし、わずかに変更されたSSHクライアントを使用して、設計時に意図されていなかった方法でプロトコルを使用することをいとわない場合は、実現することができます。これについては、以下で詳しく説明します。

それが不可能な理由

クライアントは、SSHプロトコルの一部としてホスト名を送信しません。

DNSルックアップの一部としてホスト名を送信する可能性がありますが、それはキャッシュされる可能性があり、クライアントからリゾルバーを経由して信頼できるサーバーへのパスはプロキシを通過しない可能性があり、特定のDNSルックアップを関連付ける確実な方法がない場合でも特定のSSHクライアント。

また、SSHプロトコル自体を使ってできる特別なこともありません。クライアントからSSHバージョンのバナーを見ることさえせずにサーバーを選択する必要があります。プロキシに何かを送信する前に、クライアントにバナーを送信する必要があります。サーバーからのバナーは異なる場合があり、どちらを使用するのが正しいかを推測することはできません。

このバナーは暗号化されずに送信されますが、変更することはできません。そのバナーのすべてのビットは接続のセットアップ中に検証されるため、少し下で接続障害が発生することになります。

この接続を機能させるには、クライアント側で何かを変更する必要があります。

ほとんどの回避策は、SSHトラフィックを別のプロトコル内にカプセル化することです。また、クライアントが送信するバージョンバナーにホスト名が含まれるSSHプロトコル自体への追加を想像することもできます。バナーの一部は現在フリーフォーム識別フィールドとして指定されているため、これは既存のサーバーとの互換性を保つことができ、クライアントは通常、サーバーからのバージョンバナーを待ってから独自のバージョンバナーを送信しますが、プロトコルはクライアントがバナーを送信することを許可します最初。最近のバージョンのsshクライアント(Ubuntu 14.04など)は、サーバーバナーを待たずにバナーを送信します。

このバナーにサーバーのホスト名を含める手順を実行しているクライアントは知りません。そのような機能を追加するために パッチOpenSSHメーリングリスト に送信しました。しかし、SSHトラフィックを覗き見している人にホスト名を公開したくないという欲求に基づいて拒否されました。秘密のホスト名は基本的に名前ベースのプロキシの操作と互換性がないので、SSHプロトコルの公式のSNI拡張がすぐに表示されるとは期待しないでください。

実際のソリューション

私にとって最も効果的な解決策は、実際にはIPv6を使用することでした。

IPv6では、各サーバーに個別のIPアドレスを割り当てることができるため、ゲートウェイは宛先IPアドレスを使用して、パケットを送信するサーバーを見つけることができます。 SSHクライアントは、Teredoを使用してIPv6アドレスを取得する唯一の方法であるネットワークで実行されている場合があります。 Teredoは信頼できないことがわかっていますが、接続のネイティブIPv6エンドがパブリックTeredoリレーを使用している場合のみです。プロキシを実行するゲートウェイにTeredoリレーを配置するだけです。 Miredoは、5分未満でリレーとしてインストールおよび構成できます。

回避策

ジャンプホスト/要塞ホストを使用できます。このアプローチは、個々のサーバーのSSHポートをパブリックインターネットに直接公開したくない場合を対象としています。 SSHに必要な外部に向けられたIPアドレスの数を減らすという追加の利点があります。そのため、このシナリオで使用できます。これは、セキュリティ上の理由から別の保護層を追加することを目的としたソリューションであるという事実は、追加のセキュリティが必要ないときにそれを使用することを妨げるものではありません。

ssh -o ProxyCommand='ssh -W %h:%p user1@bastion' user2@target

実際のソリューション(IPv6)が範囲外にある場合に動作させるためにハッキングするのは簡単ではありません

私が説明しようとしているハックは、絶対に最後の手段としてのみ使用されるべきです。このハックの使用について考える前に、SSHを介して外部から到達可能にしたい各サーバーのIPv6アドレスを取得することを強くお勧めします。 SSHサーバーにアクセスするための主要な方法としてIPv6を使用し、IPv6の展開に影響を与えないIPv4のみのネットワークからSSHクライアントを実行する必要がある場合にのみ、このハックを使用してください。

クライアントとサーバー間のトラフィックは完全に有効なSSHトラフィックである必要があるという考え方です。しかし、プロキシは、ホスト名を識別するためにパケットのストリームについて十分に理解する必要があるだけです。 SSHはホスト名を送信する方法を定義していないため、代わりにそのような可能性を提供する他のプロトコルを検討できます。

HTTPとHTTPSはどちらも、サーバーがデータを送信する前にクライアントがホスト名を送信できるようにします。ここでの問題は、SSHトラフィックとして、またHTTPとHTTPSのいずれかとして同時に有効なバイトストリームを構築できるかどうかです。 HTTPsそれはほとんどスターターではありませんが、HTTPは可能です(HTTPの十分に寛大な定義のために)。

SSH-2.0-OpenSSH_6.6.1 / HTTP/1.1
$: 
Host: example.com

これはSSHまたはHTTPのように見えますか?これはSSHであり、完全にRFCに準拠しています(ただし、一部のバイナリ文字は、SFレンダリングによって少し破損しています)。

SSHバージョン文字列にはコメントフィールドが含まれ、上記では値/ HTTP/1.1が含まれています。改行の後、SSHにはいくつかのバイナリパケットデータがあります。最初のパケットは、クライアントによって送信され、サーバーによって無視されたMSG_SSH_IGNOREメッセージです。無視されるペイロードは次のとおりです。

: 
Host: example.com

HTTPプロキシが受け入れるものに十分寛容な場合、同じバイトシーケンスがSSH-2.0-OpenSSH_6.6.1と呼ばれるHTTPメソッドとして解釈され、無視メッセージの先頭のバイナリデータはHTTPヘッダー名として解釈されます。

プロキシは、HTTPメソッドも最初のヘッダーも理解しません。しかし、バックエンドを見つけるために必要なすべてのHostヘッダーを理解できます。

これが機能するためには、バックエンドを見つけるのに十分なHTTPを理解するだけでよいという原則に基づいてプロキシを設計する必要があります。バックエンドが見つかると、プロキシは生のバイトストリームを渡して実際の終端を残すだけです。バックエンドによって行われるHTTP接続の。

HTTPプロキシについて非常に多くの仮定を行うことは、少しストレッチのように聞こえるかもしれません。しかし、SSHをサポートすることを目的として開発された新しいソフトウェアをインストールしても構わないとしたら、HTTPプロキシの要件はそれほど悪くありません。

私自身の場合、この方法は、コード、構成などに変更を加えることなく、すでにインストールされているプロキシで機能することがわかりました。これは、HTTPのみでSSHを考慮しないで書かれたプロキシ用です。

概念実証 client および proxy 。 (プロキシは私が運営するサービスであることの免責事項。他のプロキシがこの使用をサポートすることが確認されたら、リンクを自由に置き換えてください。)

このハックの注意事項

  • 使用しないでください。実際のソリューションであるIPv6を使用することをお勧めします。
  • プロキシがHTTPトラフィックを理解しようとすると、確実に機能しなくなります。
  • 変更されたSSHクライアントに依存するのは良いことではありません。
19
kasperd

私は間違っていると証明されたいのですが、これは少なくともあなたが説明した方法では可能だと思います。クライアントが接続したいホスト名を送信しているようには見えません(少なくとも平文で)。 SSH接続の最初のステップは、暗号化を設定することです。

さらに、ホストキーの検証に問題が発生します。 SSHクライアントは、IPアドレスとホスト名に基づいてキーを検証します。キーが異なる複数のホスト名がありますが、接続しているIPは同じです。

可能な解決策は、クライアントがそのマシンにsshで入り、通常の(または必要に応じて制限された)シェルを取得し、そこから内部ホストにsshできる「要塞」ホストを持つことです。

3
Mark

ブロックに新しい子供がいます。 SSHパイパーは、事前定義されたユーザー名に基づいて接続をルーティングします。これは、内部ホストにマップされる必要があります。これは、リバースプロキシのコンテキストで最適なソリューションです。

githubのSSh piper

私の最初のテストでは、SSHとSFTPの両方が機能することが確認されました。

3
Király István

プロキシモードを備えたHoneytrap(低対話型ハニーポット)は、それを実現するために変更できないのかと思います。

このハニーポットは、任意のプロトコルを別のコンピュータに転送できます。名前ベースのvhostシステム(Apacheによって実装されている)を追加すると、どのプロトコルに対しても完全なリバースプロキシになる可能性があります。

私にはそれを達成するスキルはありませんが、多分それは素晴らしいプロジェクトかもしれません。

2
Kafeine

ファイアウォールの背後でアクセスするポート/ホストの数が増えると、VPNの利便性が高まります。

VPNは好きではありません。

1
alex

sshのしくみが原因で、それは不可能だと思います。 httpsと同様に、ssh内のすべてが暗号化されているため、ゲートウェイはどこに接続したいのかわからないため、ホストごとに異なる(外部)IPが必要になります。

1
Jure1873