Existe-t-il un proxy inverse SSH basé sur un hôte virtuel?

36

Je suis devenu un passionné des proxy inversés HTTP dans notre environnement de développement et j'ai trouvé le proxy inverse de l'hôte virtuel basé sur DNS très utile. Le fait d'avoir un seul port (et le port standard) ouvert sur le pare-feu facilite grandement la gestion.

J'aimerais trouver quelque chose de similaire pour faire des connexions SSH mais je n'ai pas eu beaucoup de chance. Je préférerais ne pas utiliser simplement le tunneling SSH car cela nécessite l'ouverture de plages de ports autres que la norme. Y a-t-il quelque chose qui puisse faire ça?

Est-ce que HAProxy pourrait le faire?

Ahanson
la source
Le transfert de fichier de votre application envisagée ou votre accès SSH réel aux hôtes?
Kyle Hodgson le
L’objectif est un accès SSH direct à l’hôte. Ce besoin découle du désir de faire fonctionner un serveur Mercurial en interne, mais notre serveur est derrière le pare-feu. En ce moment, je travaille simplement à mettre en place une version HTTP, mais je voulais que les commits utilisent SSH au lieu de HTTP. L'accès SSH direct à d'autres serveurs serait un bonus si cela était possible.
ahanson
C'est un problème tellement agaçant.
partialité
D'après ce que j'ai compris, HAProxy prend désormais en charge cette fonctionnalité via SNI. Bien que je n'ai pas encore réussi à le faire.
Carel

Réponses:

24

Je ne crois pas que la SSH basée sur le nom soit une chose possible étant donné le fonctionnement du protocole.

Voici quelques alternatives.

  • Vous pouvez configurer l’hôte qui répond pour que le port 22 joue le rôle de passerelle. Ensuite, vous pouvez configurer le serveur ssh pour transférer les demandes vers l’intérieur en fonction de la clé. Exemple de passerelle SSH avec des clés

  • Vous pouvez adapter votre client à utiliser cet hôte comme proxy. En d’autres termes, il enverrait ssh à l’hôte passerelle, puis utiliserait cet hôte pour établir une connexion avec l’hôte interne. Proxy SSH avec configuration client .

  • Vous pouvez également installer un proxy http simple sur le bord. Ensuite, utilisez-le pour autoriser les connexions entrantes. SSH via un proxy HTTP .

Évidemment, avec tout ce qui précède, il est très important de configurer et de verrouiller correctement la passerelle.

Zoredache
la source
18

Je cherche une solution à ce problème par intermittence depuis 16 mois. Mais chaque fois que je regarde, il semble impossible de faire cela avec le protocole SSH tel que spécifié dans les RFC pertinents et mis en œuvre par des implémentations majeures.

Toutefois, si vous êtes prêt à utiliser un client SSH légèrement modifié et à utiliser des protocoles d’une manière qui n’était pas exactement prévue au moment de leur conception, il est alors possible d’y parvenir. Plus à ce sujet ci-dessous.

Pourquoi ce n'est pas possible

Le client n'envoie pas le nom d'hôte dans le cadre du protocole SSH.

Il peut envoyer le nom d’hôte dans le cadre d’une recherche DNS, mais cela peut être mis en cache et le chemin du client via les résolveurs aux serveurs faisant autorité ne croise pas le proxy. Même s’il le faisait, il n’existait aucun moyen robuste d’associer des recherches DNS spécifiques à clients SSH spécifiques.

Il n'y a rien d'extraordinaire à faire avec le protocole SSH lui-même. Vous devez choisir un serveur sans même avoir vu la bannière de la version SSH du client. Vous devez envoyer une bannière au client avant qu’il n’envoie quoi que ce soit au proxy. Les bannières des serveurs peuvent être différentes, et vous n’avez aucune chance de deviner lequel est le bon.

Même si cette bannière est envoyée non chiffrée, vous ne pouvez pas la modifier. Chaque bit de cette bannière sera vérifié lors de l’établissement de la connexion, ce qui entraînera un échec de connexion un peu plus tard.

Pour moi, la conclusion est claire: il faut changer quelque chose du côté du client pour que cette connectivité fonctionne.

La plupart des solutions de contournement encapsulent le trafic SSH dans un protocole différent. On pourrait aussi imaginer un ajout au protocole SSH lui-même, dans lequel la bannière de version envoyée par le client comprend le nom d’hôte. Cela peut rester compatible avec les versions existantes, puisqu’une partie de la bannière est actuellement spécifiée en tant que champ d’identification de formulaire libre. Bien que les clients attendent généralement la bannière de version du serveur avant d’envoyer le leur, le protocole permet au client d’envoyer leur bannière. première. Certaines versions récentes du client ssh (par exemple celle d’Ubuntu 14.04) envoient la bannière sans attendre la bannière du serveur.

Je ne connais aucun client qui aurait pris des mesures pour inclure le nom d'hôte du serveur dans cette bannière. J'ai envoyé un correctif à la liste de diffusion OpenSSH pour ajouter une telle fonctionnalité. Mais il a été rejeté pour ne pas révéler le nom d'hôte à quiconque surveillant le trafic SSH. Étant donné qu'un nom d'hôte secret est fondamentalement incompatible avec le fonctionnement d'un proxy basé sur un nom, ne vous attendez pas à voir une extension SNI officielle pour le protocole SSH de si tôt.

Une vraie solution

La solution qui fonctionnait le mieux pour moi était en réalité d'utiliser IPv6.

Avec IPv6, je peux attribuer une adresse IP distincte à chaque serveur. Ainsi, la passerelle peut utiliser l'adresse IP de destination pour déterminer le serveur auquel envoyer le paquet. Les clients SSH peuvent parfois fonctionner sur des réseaux où le seul moyen d'obtenir une adresse IPv6 serait d'utiliser Teredo. On sait que Teredo n'est pas fiable, mais uniquement lorsque l'extrémité IPv6 native de la connexion utilise un relais Teredo public. On peut simplement mettre un relais Teredo sur la passerelle, où vous exécuteriez le proxy. Miredo peut être installé et configuré en tant que relais en moins de cinq minutes.

Une solution de contournement

Vous pouvez utiliser un hôte de saut / hôte bastion. Cette approche est destinée aux cas dans lesquels vous ne souhaitez pas exposer directement le port SSH des serveurs individuels à Internet. Il présente en outre l'avantage de réduire le nombre d'adresses IP externes dont vous avez besoin pour SSH, raison pour laquelle il est utilisable dans ce scénario. Le fait qu'il s'agisse d'une solution destinée à ajouter une autre couche de protection pour des raisons de sécurité ne vous empêche pas de l'utiliser si vous n'avez pas besoin de la sécurité supplémentaire.

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

Un sale coup à faire pour que ça marche si la vraie solution (IPv6) est hors de portée

Le hack que je suis sur le point de décrire ne devrait être utilisé qu'en dernier recours. Avant même de penser à utiliser ce hack, je vous recommande fortement de fournir une adresse IPv6 pour chacun des serveurs que vous souhaitez pouvoir atteindre de manière externe via SSH. Utilisez IPv6 comme méthode principale pour accéder à vos serveurs SSH et utilisez ce hack uniquement lorsque vous devez exécuter un client SSH à partir d'un réseau exclusivement IPv4 sur lequel vous n'avez aucune influence sur le déploiement d'IPv6.

L'idée est que le trafic entre le client et le serveur doit être un trafic SSH parfaitement valide. Mais le proxy doit seulement comprendre suffisamment le flux de paquets pour identifier le nom d'hôte. Comme SSH ne définit pas de méthode pour envoyer un nom d’hôte, vous pouvez envisager d’autres protocoles offrant une telle possibilité.

HTTP et HTTPS permettent tous deux au client d'envoyer un nom d'hôte avant que le serveur n'envoie des données. La question est maintenant de savoir s'il est possible de construire un flux d'octets qui est simultanément valide en tant que trafic SSH et en tant que HTTP et HTTPS. HTTP est quasiment un non-démarreur, mais HTTP est possible (pour des définitions de HTTP suffisamment libérales).

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

Est-ce que cela ressemble à SSH ou HTTP pour vous? Il est compatible avec SSH et RFC (sauf que certains des caractères binaires ont été endommagés par le rendu de SF).

La chaîne de version SSH comprend un champ de commentaire qui, dans ce qui précède, a la valeur / HTTP/1.1. Après la nouvelle ligne, SSH a quelques données de paquets binaires. Le premier paquet est un MSG_SSH_IGNOREmessage envoyé par le client et ignoré par le serveur. La charge à ignorer est:

: 
Host: example.com

Si un proxy HTTP est suffisamment libéral dans ce qu'il accepte, alors la même séquence d'octets serait interprétée comme une méthode HTTP appelée SSH-2.0-OpenSSH_6.6.1et les données binaires au début du message ignorer seraient interprétées comme un nom d'en-tête HTTP.

Le proxy ne comprendrait ni la méthode HTTP ni le premier en-tête. Mais il pourrait comprendre l'en- Hosttête, qui est tout ce dont il a besoin pour trouver le backend.

Pour que cela fonctionne, le proxy doit être conçu sur le principe qu'il suffit de comprendre suffisamment de HTTP pour trouver le backend, et une fois que le backend a été trouvé, le proxy passera simplement le flux d'octets brut et laissera la véritable terminaison. de la connexion HTTP à effectuer par le serveur.

Cela peut sembler un peu exagéré de faire autant d'hypothèses sur le proxy HTTP. Mais si vous êtes prêt à installer un nouveau logiciel développé dans l’intention de prendre en charge SSH, les conditions requises pour le proxy HTTP ne semblent pas trop mauvaises.

Dans mon cas, je trouvais que cette méthode fonctionnait sur un proxy déjà installé sans modification du code, de la configuration ou autre. Et c'était pour un proxy écrit avec uniquement HTTP et pas SSH à l'esprit.

Preuve de concept client et proxy . (Avertissement: le proxy est un service que je gère. N'hésitez pas à remplacer le lien une fois que tout autre proxy aura été confirmé pour prendre en charge cet usage.)

Mises en garde de ce hack

  • Ne l'utilisez pas. Il vaut mieux utiliser la vraie solution, IPv6.
  • Si le proxy tente de comprendre le trafic HTTP, il va sûrement casser.
  • Compter sur un client SSH modifié n’est pas une bonne chose.
Kasperd
la source
Pouvez-vous préciser ce que vous entendez par the gateway can use the destination IP address to find out which server to send the packet tola solution IPv6?
Jacob Ford
@JacobFord La clé pour comprendre cette phrase est que j'utilise le mot gateway, pas proxy . Avec IPv6, vous obtenez suffisamment d'adresses IP pour en attribuer une à chaque hôte tout en conservant des adresses en réserve. Toutes les machines que vous placeriez derrière le proxy auraient leur propre adresse IP, ce à quoi les noms seraient résolus. Pour que vous n'ayez plus besoin d'un proxy, les clients envoient leur trafic à l'adresse IP de l'hôte souhaité et vous pouvez y acheminer le trafic directement.
Kasperd
pour la solution de contournement, il existe un commutateur de commande relativement nouveau pour ssh -J, vous pouvez donc utiliser: ssh -J utilisateur1 @ utilisateur avant @ cible
PMN
3

Je ne crois pas que ce soit possible, du moins comme vous l'avez décrit, même si j'aimerais beaucoup avoir tort. Il ne semble pas que le client envoie le nom d’hôte auquel il souhaite se connecter (du moins en clair). La première étape de la connexion SSH semble être la configuration du cryptage.

En outre, la vérification de la clé de l'hôte poserait des problèmes. Les clients SSH vérifieront les clés en fonction d'une adresse IP et d'un nom d'hôte. Vous auriez plusieurs noms d'hôte avec des clés différentes, mais la même adresse IP que celle à laquelle vous vous connectez.

Une solution possible serait d'avoir un hôte 'bastion', où les clients peuvent ssh entrer sur cette machine, obtenir un shell normal (ou restreint si nécessaire) et ensuite aller ssh dans les hôtes internes.

marque
la source
Le concept de bastion est ce que nous avons actuellement configuré mais pose problème pour mon contrôle de version (sans effort supplémentaire).
ahanson
C'est super ennuyeux que ssh n'envoie pas le fqdn et gère le DNS du côté client. J'imagine que les gens ne s'inquiétaient pas du gonflement IP public ou du NAT lorsque la plupart des protocoles au niveau de l'application TCP / IP ont été créés. Parce que sérieusement, vous devriez être capable de faire du NAT basé sur un nom de domaine complet avec iptables (c'est-à-dire des filtres de noyau).
Biais
La clé d'hôte pourrait être la clé du proxy inverse. C'est un avantage si vous faites confiance à la sécurité du backend, puisque vous avez le contrôle du réseau interne et des hôtes.
Rox0r
@bias Vous ne pouvez pas faire de NAT basé sur le nom d'hôte, même si le protocole de niveau supérieur envoie le nom d'hôte. La raison pour laquelle cela ne peut pas être fait est que le choix du backend doit être fait lors de la réception du paquet SYN, mais que le nom d'hôte n'est envoyé qu'après le traitement de SYN et le retour d'un SYN-ACK. Vous pouvez toutefois utiliser un proxy de couche d'application très mince pour les protocoles qui envoient un nom d'hôte, tels que http et https.
Kasperd
3

Il y a un nouveau gamin sur le bloc. SSH Piper acheminera votre connexion en fonction de noms d’utilisateur prédéfinis, qui doivent être mappés aux hôtes internes. C'est la meilleure solution dans le contexte du reverse-proxy.

SSh Piper sur github

Mes premiers tests ont confirmé, SSH et SFTP fonctionnent tous les deux.

Király István
la source
C'est effectivement une attaque de MITM. Je m'attends à ce qu'il casse dans toutes les configurations protégées contre les attaques MITM.
Kasperd
1
En fait, la partie organisatrice est à la fois l'hôte et l'homme du milieu, de sorte que seuls ces deux-là sont impliqués.
Király István
@ KirályIstván c'est un projet génial et la preuve que les autres réponses ne sont pas 100% correctes. J'ai créé un outil similaire basé sur github.com/gliderlabs/sshfront et quelques bash / python (je ne peux pas l'ouvrir au source mais ce n'est pas intéressant - bash utilise ssh client et python est utilisé comme gestionnaire d'authentification). Mais j'ai un problème avec la solution actuelle. Il ne supporte pas sftp (scp fonctionne). Il se bloque en essayant d'exécuter le sous-système debug1: Sending subsystem: sftp. Il s'avère que le devant de la chemise ne supporte pas les sous-systèmes. Est-ce que vous soutenez l'ourlet dans le piper SSh?
Maciek Sawicki
1
@ MaciekSawicki Je ne suis pas l'auteur. Je viens de l'utiliser dans mon projet. .)
Király István
2

Je me demande si Honeytrap (le pot de miel à faible interaction) qui a un mode proxy ne pourrait pas être modifié pour atteindre cet objectif.

Ce pot de miel est capable de transférer n'importe quel protocole vers un autre ordinateur. Ajouter un système vhost basé sur le nom (tel qu’implémenté par Apache) pourrait en faire un proxy inverse parfait pour tout protocole non?

Je n’ai pas les compétences pour y parvenir, mais peut-être que ce serait un très bon projet.

Kafeine
la source
excellente idée!
partialité
1
La fonctionnalité vhost dans Apache repose sur l'envoi par le client du nom d'hôte avant l'envoi des données par le serveur. Le protocole SSH n'impliquant pas un tel nom d'hôte, je ne vois pas comment vous pourriez même commencer à implémenter une telle fonctionnalité. Mais si vous pouviez développer vos idées, je serais heureux de mettre en œuvre une preuve de concept ou de vous dire pourquoi cela ne fonctionnerait pas.
Kasperd
1

À mesure que le nombre de ports / hôtes auxquels vous souhaitez accéder derrière un pare-feu augmente, la commodité des VPN augmente.

Je n'aime pas les VPN, cependant.

alex
la source
1

à cause de la façon dont ssh fonctionne, je pense que ce n'est pas possible. Semblable à https, vous devez avoir différentes adresses IP (externes) pour différents hôtes, car la passerelle ne sait pas où vous souhaitez vous connecter car tout dans ssh est chiffré.

Jure1873
la source