是否有基于名称的虚拟主机SSH反向代理?


36

我已经在开发环境中非常喜欢HTTP反向代理,并且发现基于DNS的虚拟主机反向代理非常有用。在防火墙上仅打开一个端口(和标准端口)可以简化管理。

我想找到类似的方法来进行SSH连接,但是运气不高。我不想简单地使用SSH隧道,因为这需要打开标准端口以外的端口范围。有什么可以做到的吗?

HAProxy可以这样做吗?


您是否打算传输应用程序文件或对主机的实际SSH访问?
凯尔·霍奇森

目标是直接SSH访问主机。这种需求源于内部运行Mercurial服务器的愿望,但我们的服务器位于防火墙后面。现在,我正在简单地设置HTTP版本,但我想使用SSH而不是HTTP进行提交。如果可能的话,直接SSH访问其他服务器将是一个好处。
ahanson

这是一个令人讨厌的问题。
偏差

我的理解是HAProxy现在通过SNI支持此功能。尽管我还无法做到这一点。
卡雷尔

Answers:


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上的ssh客户端)的确发送了横幅,而无需等待服务器横幅。

我不知道任何客户端,该客户端已采取措施在此横幅中包含服务器的主机名。我已经向OpenSSH邮件列表发送了补丁,以添加这样的功能。但这是因为不希望向侦听SSH流量的任何人透露主机名而被拒绝。由于秘密主机名从根本上与基于名称的代理的操作不兼容,因此不要指望很快就可以看到SSH协议的正式SNI扩展。

真正的解决方案

最适合我的解决方案实际上是使用IPv6。

使用IPv6,我可以为每个服务器分配一个单独的IP地址,因此网关可以使用目标IP地址来查找将数据包发送到哪个服务器。SSH客户端有时可能在网络上运行,而要获得IPv6地址的唯一方法是使用Teredo。已知Teredo是不可靠的,但是仅当连接的本机IPv6端使用公共Teredo中继时才如此。只需将Teredo中继放在运行代理的网关上即可。Miredo可以在不到五分钟的时间内安装和配置为中继。

解决方法

您可以使用跳转主机/堡垒主机。此方法适用于您不想将单个服务器的SSH端口直接公开到公共Internet的情况。它确实具有减少SSH所需的面向外部IP地址的数量的额外好处,这就是在这种情况下可以使用它的原因。出于安全原因,它是旨在添加另一层保护的解决方案,这一事实并不能阻止您在不需要增加的安全性时使用它。

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

如果真正的解决方案(IPv6)不在您的范围之内,则可以尝试使之工作

我将要描述的hack只能用作绝对不得已的手段。在您甚至没有考虑使用此hack之前,我强烈建议您为要通过SSH从外部访问的每个服务器获取一个IPv6地址。将IPv6用作访问SSH服务器的主要方法,并且仅在需要从仅支持IPv4的网络运行SSH客户端(对部署IPv6没有任何影响)时才使用此技巧。

这个想法是,客户端和服务器之间的流量必须是完全有效的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代理在接受的内容上足够自由,那么相同的字节序列将被解释为HTTP方法SSH-2.0-OpenSSH_6.6.1,而忽略消息开始处的二进制数据将被解释为HTTP标头名称。

代理不会理解HTTP方法或第一个标头。但是它可以理解Host标题,这是找到后端所需要的。

为了使此工作正常进行,必须按以下原则设计代理:只需要了解足够的HTTP即可找到后端,一旦找到后端,代理将简单地传递原始字节流并保留实际终止HTTP连接由后端完成。

对HTTP代理进行如此多的假设听起来有点费力。但是,如果您愿意安装旨在支持SSH的新软件,那么对HTTP代理的要求听起来不会太糟糕。

就我自己而言,我发现此方法可以在已安装的代理上工作,而无需更改代码,配置或其他方式。这是针对只使用HTTP而没有考虑SSH编写的代理。

概念客户代理的证明。(免责声明代理是我提供的服务。一旦确认有任何其他代理支持此用法,请随时替换链接。)

此hack的警告

  • 不要使用它。最好使用真正的解决方案,即IPv6。
  • 如果代理尝试了解HTTP流量,则肯定会中断。
  • 依靠修改后的SSH客户端是不好的。

您能否详细说明the gateway can use the destination IP address to find out which server to send the packet toIPv6解决方案中的含义?
雅各布·福特

@JacobFord理解该句子的关键是我使用网关一词而不是proxy。使用IPv6,您可以获得足够的IP地址,可以为每个主机分配一个IP地址,但仍有地址可供使用。您放置在代理后面的所有计算机都将拥有自己的IP地址,这就是名称所解析的。因此,您不再需要代理,客户端将其流量发送到所需主机的IP地址,您可以将流量直接路由到那里。
卡巴斯德(Kasperd)'18年

对于变通部分,ssh有一个相对较新的命令开关-J,因此您可以使用:ssh -J user1 @ front user2 @ target
PMN

3

我不相信这是可能的,至少按照您的描述,尽管我很想证明自己是错误的。客户端似乎没有发送它希望连接的主机名(至少是明文形式的)。SSH连接的第一步似乎是设置加密。

此外,您还会遇到主机密钥验证问题。SSH客户端将根据IP地址和主机名验证密钥。您将拥有多个具有不同密钥的主机名,但是您要连接的IP地址相同。

可能的解决方案是拥有一个“堡垒”主机,客户端可以在其中插入该计算机,获取常规的(或需要的话受限制的)shell,然后可以从那里将其装入内部主机。


堡垒概念是我们当前已设置的,但对于我的版本控制而言是个问题(无需额外的努力)。
ahanson

ssh不发送fqdn并在客户端处理DNS真是太烦人了。我猜人们在创建大多数TCP / IP应用程序级别协议时不必担心公共IP膨胀和NAT。因为,认真地讲,您应该能够使用iptables(即内核过滤器)进行基于FQDN的NAT。
偏差

主机密钥可以是反向代理的密钥。如果您信任后端的安全性,那么这是一个好处,因为您可以控制内部网络和主机。
rox0r

@bias即使更高级别的协议确实发送了主机名,您也无法基于主机名进行NAT。无法完成此操作的原因是,必须在接收到SYN数据包时选择后端,但是只有在处理完SYN并返回SYN-ACK之后才发送主机名。但是,对于可以发送主机名的协议(例如http和https),可以使用非常薄的应用程序层代理。
kasperd 2014年

3

街上有个新孩子。SSH管道程序将根据预定义的用户名路由您的连接,该用户名应映射到内部主机。这是反向代理上下文中的最佳解决方案。

GitHub上的SSh Piper

我的第一个测试确认,SSH和SFTP都可以工作。


这实际上是一次MITM攻击。我希望它能在防止MITM攻击的每个设置中突破。
卡巴斯德(Kasperd),

1
实际上,主办方既是主持人又是中间的人,因此只有这两个参与。
基拉伊伊什特万

@KirályIstván这是一个很棒的项目,并证明其他答案也不是100%正确的。我基于github.com/gliderlabs/sshfront和一些bash / python 创建了类似的工具(我无法将其开源,但这并不有趣-bash运行ssh客户端,并且python被用作身份验证处理程序)。但是我目前的解决方案有一个问题。它不支持sftp(scp可以工作)。尝试运行子系统时挂起debug1: Sending subsystem: sftp。事实证明,前衬衫不支持子系统。您支持SSh吹笛者的下摆吗?
Maciek Sawicki

1
@MaciekSawicki我不是作者。我只是在我的项目中使用它。。)
KirályIstván18-3-29

2

我想知道是否不能修改具有代理模式的Honeytrap(低交互蜜罐)来实现这一目标。

此蜜罐能够将任何协议转发到另一台计算机。添加基于名称的虚拟主机系统(由Apache实施)可以使其成为任何协议的理想反向代理。

我没有达到目标的技能,但也许这可能是一个伟大的项目。


好主意!
偏差

1
Apache中的vhost功能依赖于客户端在从服务器发送任何数据之前发送主机名。SSH协议不涉及这样的主机名,因此我什至看不到您如何开始实现这样的功能。但是,如果您可以详细说明自己的想法,我很乐意实施概念验证或告诉您为什么它不起作用。
kasperd 2014年

1

随着您要在防火墙后面访问的端口/主机数量的增加,VPN的便利性也随之增加。

不过,我不喜欢VPN。


1

由于ssh的工作原理,我认为这是不可能的。与https相似,您必须为不同的主机使用不同的(外部)IP,因为网关不知道您想连接到哪里,因为ssh中的所有内容均已加密

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.