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


36

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

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

HAProxyはこれを実行できますか?


意図したアプリケーションファイル転送ですか、それともホストへの実際のSSHアクセスですか?
カイルホジソン

ホストへの直接SSHアクセスが目標です。この必要性は、Mercurialサーバーを社内で実行したいという要望から来ていますが、サーバーはファイアウォールの内側にあります。現在、私は単純にHTTPバージョンのセットアップに取り組んでいますが、コミットではHTTPの代わりにSSHを使用したかったのです。これが可能であれば、他のサーバーへの直接SSHアクセスがボーナスになります。
ahanson

これは非常に厄介な問題です。
バイアス

私の理解では、HAProxyはSNIを介してこれをサポートするようになりました。まだこれを実現することはできませんでしたが。
カレル

回答:


24

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

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

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

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

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

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


18

過去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クライアントは、IPv6アドレスを取得する唯一の方法がTeredoを使用するネットワーク上で実行されている場合があります。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の両方として同時に有効なバイトストリームを構築できるかどうかです。HTTPでは、ほとんどスターターではありませんが、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プロキシが受け入れる内容が十分に自由な場合、同じバイトシーケンスが呼び出されるHTTPメソッドとして解釈されSSH-2.0-OpenSSH_6.6.1、無視メッセージの先頭のバイナリデータはHTTPヘッダー名として解釈されます。

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

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

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

私自身の場合、このメソッドは、コード、構成などを変更せずに、既にインストールされているプロキシで動作することがわかりました。そして、これはHTTPのみでSSHを考慮しないで書かれたプロキシ用でした。

概念実証のクライアントプロキシ。(プロキシは私が運営するサービスであるという免責事項。他のプロキシがこの使用をサポートしていることが確認されたら、リンクを交換してください。)

このハックの注意事項

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

the gateway can use the destination IP address to find out which server to send the packet toIPv6ソリューションで、あなたが意味することを詳しく説明できますか?
ジェイコブフォード

@JacobFordこの文を理解する鍵は、プロキシではなくゲートウェイという言葉を使用することです。IPv6を使用すると、すべてのホストに1つを割り当てるのに十分なIPアドレスが得られますが、それでも予備のアドレスがあります。プロキシの背後に配置するマシンはすべて、独自のIPアドレスを持ちます。これは、名前を解決するものです。そのため、プロキシは不要になり、クライアントはトラフィックを目的のホストのIPアドレスに送信し、そこで直接トラフィックをルーティングできます。
カスペルド

回避策部分には、sshの比較的新しいコマンドスイッチがあるため-J、次を使用できます。ssh -J user1 @ front user2 @ target
PMN

3

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

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

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


要塞の概念は、現在セットアップされているものですが、バージョン管理には問題があります(余分な労力なし)。
ahanson

sshがfqdnを送信せず、クライアント側でDNSを処理することは非常に面倒です。ほとんどのTCP / IPアプリケーションレベルのプロトコルが作成されたとき、人々はパブリックIPの膨張とNATについて心配しなかったと思います。真剣に、iptables(つまり、カーネルフィルター)でFQDNベースのNATを実行できる必要があるためです。
バイアス

ホストキーは、リバースプロキシのキーである可能性があります。内部ネットワークとホストを制御できるため、バックエンドのセキュリティを信頼する場合、これは利点です。
-rox0r

@bias上位プロトコルがホスト名を送信する場合でも、ホスト名に基づいてNATを実行することはできません。実行できない理由は、SYNパケットを受信したときにバックエンドを選択する必要があるが、ホスト名はSYNが処理されてSYN-ACKが返された後にのみ送信されるためです。ただし、httpやhttpsなどのホスト名を送信するプロトコルには、非常に薄いアプリケーションレイヤープロキシを使用できます。
カスペルド14

3

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

GitHubのSShパイパー

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


これは事実上MITM攻撃です。MITM攻撃から保護されているすべてのセットアップで破損することを期待しています。
カスペルド

1
実際には、ホスティングパーティは、ホストと中間の男性の両方であるため、これらの2つだけが関与しています。
キラリーイストゥバン

@KirályIstvánこれは素晴らしいプロジェクトであり、他の答えが100%正しくないことを証明しています。私はgithub.com/gliderlabs/sshfrontといくつかのbash / python に基づいて同様のツールを作成しました(ソースを開くことはできませんが、それは面白くありません-bashはsshクライアントを実行し、pythonは認証ハンドラーとして使用されます)。しかし、現在のソリューションには1つの問題があります。sftpをサポートしていません(scpは動作します)。サブシステムを実行しようとしてハングしますdebug1: Sending subsystem: sftp。シャツフロントはサブシステムをサポートしていないことがわかります。SShパイパーで裾をサポートしていますか?
マシークサウィッキ

1
@MaciekSawicki私は著者ではありません。私は自分のプロジェクトでそれを使用しています。。)
キラリー・イストヴァン

2

プロキシモードを備えたHoneytrap(低相互作用ハニーポット)は、それを達成するために変更できないのではないかと思っています。

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

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


素晴らしいアイデア!
バイアス

1
Apacheのvhost機能は、サーバーからデータが送信される前にホスト名を送信するクライアントに依存しています。SSHプロトコルにはこのようなホスト名は含まれないため、このような機能の実装を開始する方法がわかりません。しかし、アイデアについて詳しく説明できる場合は、概念実証を実装するか、なぜ機能しないのかを教えていただければ幸いです。
カスペルド14

1

ファイアウォールの内側でアクセスするポート/ホストの数が増えると、VPNの利便性が向上します。

ただし、VPNは好きではありません。


1

sshの仕組みのせいで、それは不可能だと思います。httpsと同様に、sshのすべてが暗号化されているため、ゲートウェイはどこに接続したいかわからないため、異なるホストに対して異なる(外部)IPを持たなければなりません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.