Frage Gibt es einen Namen basierten virtuellen Host SSH Reverse Proxy?


Ich bin in unserer Entwicklungsumgebung auf HTTP-Reverse-Proxies gestoßen und fand den DNS-basierten virtuellen Host-Reverse-Proxy sehr nützlich. Wenn nur ein Port (und der Standard) auf der Firewall geöffnet ist, ist die Verwaltung wesentlich einfacher.

Ich würde gerne etwas Ähnliches finden, um SSH-Verbindungen zu machen, aber ich hatte nicht viel Glück. Ich würde es vorziehen, nicht einfach SSH-Tunneling zu verwenden, da dies das Öffnen von anderen Port-Bereichen als dem Standard erfordert. Gibt es da draußen etwas, das das kann?

Könnte HAProxy das tun?


33
2017-07-01 16:01


Ursprung


Ist Ihre beabsichtigte Anwendung Dateiübertragung oder tatsächlichen SSH-Zugriff auf Hosts? - Kyle Hodgson
Direkter SSH-Zugriff auf den Host ist das Ziel. Diese Notwendigkeit kommt von dem Wunsch, einen Mercurial-Server intern zu betreiben, aber unser Server befindet sich hinter der Firewall. Im Moment arbeite ich gerade an der Einrichtung einer HTTP-Version, aber ich wollte Commits SSH anstelle von HTTP verwenden. Ein direkter SSH-Zugriff auf andere Server wäre ein Bonus, wenn dies möglich wäre. - ahanson
Das ist so ein lästiges Problem. - bias
Mein Verständnis ist, dass HAProxy dies nun via SNI unterstützt. Obwohl ich es noch nicht geschafft habe. - Carel


Antworten:


Ich glaube nicht, dass namensbasiertes SSH möglich ist, wenn das Protokoll funktioniert.

Hier sind ein paar alternativen.

  • Sie können den Host, der auf Port 22 antwortet, als Gateway einrichten. Dann können Sie den SSH-Server so konfigurieren, dass Anfragen basierend auf dem Schlüssel an das Innere weitergeleitet werden. SSH Tor Beispiel mit Schlüsseln

  • Sie könnten Ihren Client so einstellen, dass er diesen Host als Proxy verwendet. Das heißt, es würde ssh an den Gateway-Host senden und dann diesen Host verwenden, um eine Verbindung zum internen Host herzustellen. SSH-Proxy mit Client Aufbau.

  • Sie könnten auch einen einfachen HTTP-Proxy am Rand einrichten. Verwenden Sie das dann, um eingehende Verbindungen zuzulassen. SSH über HTTP-Proxy.

Offensichtlich ist es bei all dem oben Gesagten wichtig, dass Sie das Gateway richtig konfigurieren und sperren.


24
2017-07-01 16:17





Ich habe in den letzten 16 Monaten immer wieder nach einer Lösung für dieses Problem gesucht. Aber jedesmal scheint es mir unmöglich, dies mit dem SSH-Protokoll zu tun, wie es in den relevanten RFCs spezifiziert und von den wichtigsten Implementierungen implementiert wird.

Wenn Sie jedoch bereit sind, einen leicht modifizierten SSH-Client zu verwenden, und Sie bereit sind, Protokolle in einer Weise zu verwenden, die bei ihrer Entwicklung nicht genau vorgesehen war, dann ist es möglich, dies zu erreichen. Mehr dazu unten.

Warum ist das nicht möglich?

Der Client sendet den Hostnamen nicht als Teil des SSH-Protokolls.

Es könnte den Hostnamen als Teil einer DNS-Suche senden, aber diese könnte zwischengespeichert werden, und der Pfad vom Client über Resolver zu autorisierenden Servern könnte den Proxy nicht passieren, und selbst wenn dies der Fall wäre, gibt es keine robuste Möglichkeit, bestimmte DNS-Lookups zuzuordnen spezifische SSH-Clients.

Es gibt nichts, was Sie mit dem SSH-Protokoll selbst machen können. Sie müssen einen Server auswählen, ohne das SSH-Versions-Banner vom Client gesehen zu haben. Sie müssen ein Banner an den Client senden, bevor es etwas an den Proxy sendet. Die Banner von den Servern können unterschiedlich sein, und Sie haben keine Chance zu erraten, welche die richtige ist.

Obwohl dieses Banner unverschlüsselt gesendet wird, können Sie es nicht ändern. Jedes Bit dieses Banners wird während des Verbindungsaufbaus überprüft, sodass Sie einen Verbindungsfehler verursachen.

Die Schlussfolgerung zu mir ist ziemlich klar, man muss etwas auf der Clientseite ändern, um diese Konnektivität funktionieren zu lassen.

Die meisten Problemumgehungen kapseln den SSH-Datenverkehr in einem anderen Protokoll. Man könnte sich auch einen Zusatz zum SSH-Protokoll vorstellen, bei dem das vom Client gesendete Versionsbanner den Hostnamen enthält. Dies kann mit vorhandenen Servern kompatibel bleiben, da ein Teil des Banners derzeit als Freiformidentifikationsfeld angegeben ist, und obwohl Clients normalerweise auf das Versionsbanner vom Server warten, bevor sie ihre eigenen senden, erlaubt das Protokoll dem Client, ihr Banner zu senden zuerst. Einige neuere Versionen des ssh-Clients (zum Beispiel der von Ubuntu 14.04) senden das Banner, ohne auf das Server-Banner zu warten.

Ich kenne keinen Client, der Schritte unternommen hat, um den Hostnamen des Servers in dieses Banner aufzunehmen. Ich habe gesendet ein Patch zum OpenSSH-Mailingliste um ein solches Feature hinzuzufügen. Aber es wurde zurückgewiesen, weil man den Hostnamen nicht jedem offenbaren wollte, der den SSH-Verkehr überwacht. Da ein geheimer Hostname grundsätzlich nicht mit dem Betrieb eines namensbasierten Proxys kompatibel ist, sollten Sie nicht erwarten, bald eine offizielle SNI-Erweiterung für das SSH-Protokoll zu sehen.

Eine echte Lösung

Die Lösung, die am besten für mich funktionierte, war IPv6 zu verwenden.

Mit IPv6 kann jedem Server eine eigene IP-Adresse zugewiesen werden, sodass das Gateway die Ziel-IP-Adresse verwenden kann, um herauszufinden, an welchen Server das Paket gesendet werden soll. Die SSH-Clients können manchmal in Netzwerken ausgeführt werden, in denen die einzige Möglichkeit, eine IPv6-Adresse zu erhalten, Teredo ist. Teredo ist bekanntlich unzuverlässig, aber nur, wenn das native IPv6-Ende der Verbindung ein öffentliches Teredo-Relay verwendet. Man kann einfach ein Teredo-Relay auf dem Gateway platzieren, wo Sie den Proxy ausführen würden. Miredo kann in weniger als fünf Minuten als Relais installiert und konfiguriert werden.

Eine Problemumgehung

Sie können einen Sprung Host / Bastion-Host verwenden. Dieser Ansatz ist für Fälle gedacht, in denen Sie den SSH-Port der einzelnen Server nicht direkt dem öffentlichen Internet aussetzen wollen. Es hat den zusätzlichen Vorteil, die Anzahl der nach außen gerichteten IP-Adresse, die Sie für SSH benötigen, zu reduzieren, weshalb es in diesem Szenario verwendbar ist. Die Tatsache, dass es sich um eine Lösung handelt, die aus Sicherheitsgründen eine weitere Schutzebene hinzufügen soll, hindert Sie nicht daran, sie zu verwenden, wenn Sie die zusätzliche Sicherheit nicht benötigen.

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

Ein Dirty to Hack, damit es funktioniert, wenn die echte Lösung (IPv6) außerhalb deiner Reichweite ist

Der Hack, den ich beschreiben werde, sollte nur als letztes Mittel verwendet werden. Bevor Sie überhaupt daran denken, diesen Hack zu verwenden, empfehle ich dringend, für jeden der Server, die extern über SSH erreichbar sein sollen, eine IPv6-Adresse zu erhalten. Verwenden Sie IPv6 als primäre Methode für den Zugriff auf Ihre SSH-Server, und verwenden Sie diesen Hack nur, wenn Sie einen SSH-Client von einem IPv4-Netzwerk aus ausführen müssen, in dem Sie keinen Einfluss auf die Bereitstellung von IPv6 haben.

Die Idee ist, dass der Verkehr zwischen Client und Server vollkommen gültiger SSH-Verkehr sein muss. Aber der Proxy muss nur genug über den Paketstrom verstehen, um den Hostnamen zu identifizieren. Da SSH keine Möglichkeit zum Senden eines Hostnamens definiert, können Sie stattdessen andere Protokolle in Betracht ziehen, die eine solche Möglichkeit bieten.

HTTP und HTTPS ermöglichen dem Client, einen Hostnamen zu senden, bevor der Server Daten gesendet hat. Die Frage ist nun, ob es möglich ist, einen Strom von Bytes zu konstruieren, der gleichzeitig als SSH-Verkehr und als HTTP und HTTPS gültig ist. HTTPs ist es ziemlich ein Nicht-Starter, aber HTTP ist möglich (für ausreichend liberale Definitionen von HTTP).

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

Sieht das für Sie wie SSH oder HTTP aus? Es ist SSH und vollständig RFC-konform (abgesehen davon, dass einige der Binärzeichen durch das SF-Rendering etwas verändert wurden).

Die SSH-Versionszeichenfolge enthält ein Kommentarfeld, das im obigen den Wert hat / HTTP/1.1. Nach dem Newline-SSH hat einige binäre Paketdaten. Das erste Paket ist a MSG_SSH_IGNORE Nachricht vom Client gesendet und vom Server ignoriert. Die zu ignorierende Nutzlast ist:

: 
Host: example.com

Wenn ein HTTP-Proxy ausreichend liberal ist, wird die gleiche Sequenz von Bytes als HTTP-Methode interpretiert SSH-2.0-OpenSSH_6.6.1 und die Binärdaten am Anfang der Ignore-Nachricht würden als HTTP-Header-Name interpretiert werden.

Der Proxy würde weder die HTTP-Methode noch den ersten Header verstehen. Aber es könnte das verstehen Host Header, was alles ist, um das Backend zu finden.

Damit dies funktionieren kann, muss der Proxy auf dem Prinzip basieren, dass er nur genug HTTP verstehen muss, um das Backend zu finden, und sobald das Backend gefunden wurde, wird der Proxy einfach den rohen Byte-Stream übergeben und die echte Beendigung verlassen der HTTP-Verbindung, die vom Backend ausgeführt werden soll.

Es mag ein bisschen wie eine Strecke klingen, um so viele Annahmen über den HTTP-Proxy zu machen. Aber wenn Sie bereit waren, eine neue Software zu installieren, die mit der Absicht entwickelt wurde, SSH zu unterstützen, dann klingen die Anforderungen für den HTTP-Proxy nicht zu schlecht.

In meinem Fall fand ich diese Methode auf einem bereits installierten Proxy ohne Änderungen an Code, Konfiguration oder anderweitig. Und das war für einen Proxy, der nur mit HTTP und ohne SSH geschrieben wurde.

Konzeptioneller Beweiß Klient und Proxy. (Haftungsausschluss, dass Proxy ein von mir betriebener Dienst ist. Fühlen Sie sich frei, den Link zu ersetzen, sobald ein anderer Proxy bestätigt wurde, um diese Nutzung zu unterstützen.)

Vorbehalte dieses Hacks

  • Benutze es nicht. Es ist besser, die echte Lösung zu verwenden, nämlich IPv6.
  • Wenn der Proxy versucht, den HTTP-Verkehr zu verstehen, wird er sicherlich brechen.
  • Sich auf einen modifizierten SSH-Client zu verlassen, ist nicht schön.

12
2017-07-08 14:54



Können Sie erläutern, was Sie meinen? the gateway can use the destination IP address to find out which server to send the packet to, in der IPv6-Lösung? - Jacob Ford
@JacobFord Der Schlüssel zum Verständnis dieses Satzes ist, dass ich das Wort verwende Tor nicht Proxy. Mit IPv6 erhalten Sie genügend IP-Adressen, um jedem Host einen zu geben und immer noch Adressen zu haben. Alle Maschinen, die Sie hinter den Proxy stellen würden, hätten ihre eigene IP-Adresse, auf die sich die Namen beziehen würden. Damit Sie keinen Proxy mehr benötigen, senden die Clients ihren Datenverkehr an die IP-Adresse des gewünschten Hosts und Sie können den Datenverkehr direkt dorthin leiten. - kasperd


Ich glaube nicht, dass dies möglich wäre, zumindest so, wie du es beschrieben hast, obwohl ich es gerne hätte, falsch bewiesen zu werden. Es scheint nicht, dass der Client den Hostnamen sendet, mit dem er sich verbinden möchte (zumindest im Klartext). Der erste Schritt der SSH-Verbindung scheint darin zu bestehen, die Verschlüsselung einzurichten.

Außerdem hätten Sie Probleme mit der Überprüfung des Hostschlüssels. SSH-Clients überprüfen Schlüssel anhand einer IP-Adresse sowie eines Hostnamens. Sie hätten mehrere Hostnamen mit unterschiedlichen Schlüsseln, aber dieselbe IP-Adresse, mit der Sie sich verbinden.

Eine mögliche Lösung wäre, einen "Bastion" -Host zu haben, wo Clients sich an diesen Rechner anschliessen können, eine normale (oder eingeschränkt, falls gewünscht) Shell erhalten und dann von dort aus auf interne Hosts zugreifen können.


3
2017-07-01 16:25



Das Bastion-Konzept ist das, was wir aktuell eingerichtet haben, aber es ist problematisch für meine Versionskontrolle (ohne zusätzlichen Aufwand). - ahanson
Es ist super ärgerlich, dass ssh die fqdn nicht sendet und das DNS auf der Clientseite behandelt. Ich denke, die Leute haben sich keine Sorgen um öffentliche IP-Bloat und NAT gemacht, als die meisten Protokolle auf TCP / IP-Anwendungsebene erstellt wurden. Weil, ernsthaft, du sollte in der Lage sein, FQDN-basiertes NAT mit iptables (d. h. Kernel-Filter) auszuführen. - bias
Der Hostschlüssel könnte der Schlüssel des Reverse-Proxy sein. Dies ist ein Vorteil, wenn Sie der Sicherheit des Back-Ends vertrauen, da Sie die Kontrolle über das interne Netzwerk und die Hosts haben. - rox0r
@bias Sie können NAT nicht basierend auf dem Hostnamen ausführen, selbst wenn das Protokoll der höheren Ebene den Hostnamen sendet. Der Grund, warum dies nicht möglich ist, ist, dass die Auswahl des Backends beim Empfang des SYN-Pakets erfolgt, aber der Hostname erst gesendet wird, nachdem das SYN verarbeitet und ein SYN-ACK zurückgegeben wurde. Sie können jedoch einen sehr dünnen Proxy für die Anwendungsschicht für Protokolle verwenden, die Hostnamen senden, z. B. http und https. - kasperd


Ich frage mich, ob Honeytrap (der Honeypot mit niedriger Interaktion), der einen Proxy-Modus hat, nicht modifiziert werden kann, um das zu erreichen.

Dieser Honeypot kann jedes Protokoll an einen anderen Computer weiterleiten. Das Hinzufügen eines namensbasierten vhost-Systems (wie von Apache implementiert) könnte es zu einem perfekten Reverse-Proxy für jedes Protokoll nein machen?

Ich habe nicht die Fähigkeiten, das zu erreichen, aber vielleicht könnte es ein großartiges Projekt sein.


2
2018-06-23 08:19



exzellente Idee! - bias
Die vhost-Funktion in Apache beruht darauf, dass der Client den Hostnamen sendet, bevor Daten vom Server gesendet wurden. Das SSH-Protokoll beinhaltet keinen solchen Hostnamen, daher sehe ich nicht, wie Sie mit der Implementierung eines solchen Features beginnen würden. Aber wenn Sie Ihre Ideen ausarbeiten können, würde ich gerne einen Proof of Concept umsetzen oder Ihnen sagen, warum es nicht funktionieren würde. - kasperd


Es ist ein neues Kind auf dem Block. SSH Piper routet Ihre Verbindung basierend auf vordefinierten Benutzernamen, die den inneren Hosts zugeordnet werden sollen. Dies ist die beste Lösung im Zusammenhang mit Reverse-Proxy.

SSh Pfeifer auf Github

Meine ersten Tests bestätigten, dass SSH und SFTP beide funktionieren.


2
2018-06-23 12:52



Das ist effektiv ein MITM-Angriff. Ich erwarte, dass es in jedem Setup bricht, das gegen MITM-Angriffe geschützt ist. - kasperd
Eigentlich ist die Gastgeberpartei sowohl der Gastgeber als auch der Mann in der Mitte, also sind nur die beiden beteiligt. - Király István
@ KirályIstván das ist genial Projekt und beweist, dass andere Antworten nicht 100% korrekt sind. Ich habe ein ähnliches Tool basierend auf erstellt github.com/gliderlabs/sshfront und etwas Bash / Python (Ich kann es nicht öffnen, aber es ist nicht so interessant - Bash läuft SSH-Client und Python wird als Auth-Handler verwendet). Aber ich habe ein Problem mit der aktuellen Lösung. Es unterstützt nicht sftp (scp funktioniert). Es hängt daran, dass versucht wird, das Subsystem auszuführen debug1: Sending subsystem: sftp . Es stellt sich heraus, dass Shirt-Front keine Subsysteme unterstützt. Unterstützen Sie den Saum in SSh Piper? - Maciek Sawicki
@MaciekSawicki Ich bin nicht der Autor. Ich benutze es einfach in meinem Projekt. .) - Király István


Da die Anzahl der Ports / Hosts, auf die Sie hinter einer Firewall zugreifen möchten, zunimmt, erhöht sich der Komfort von VPNs.

Ich mag jedoch keine VPNs.


1
2017-07-01 20:50





Weil ssh funktioniert, denke ich, dass das nicht möglich ist. Ähnlich wie https müssten Sie unterschiedliche (externe) IPs für verschiedene Hosts haben, da das Gateway nicht weiß, wo Sie sich verbinden wollen, da alles in ssh verschlüsselt ist


1
2017-07-01 22:48