作弊条:SSH 的 ProxyJump 跳板服务
问题
有些环境中,SSH服务器可能无法从Internet直接访问(例如,SSH服务器可能使用的是一个私有IP地址,或是Internet服务提供商没有提供IPv6服务,而SSH服务器只提供IPv6服务)。
考虑到SSH已经进行了相互认证(连接时客户端会验证服务器的公钥是否与已知公钥,例如 ~/.ssh/known_hosts,或是通过DNSsec发布的 SSHFP RR匹配;服务器端则会验证用户是否能证明自己拥有与授权公钥对应的私钥),因此比较常见的解决方法便是使用VPN、在防火墙上穿孔,或是使用代理服务器。
由于SSH自身也提供了许多转发功能,因此如果中间的跳板服务器也提供SSH服务,便可以使用这些跳转服务器直接作为代理服务器来用。与前面那些传统方法相比,这样做的优点是避免了安装额外的软件,也不需要特别指定端口。
ssh -W (“netcat mode”)
OpenSSH提供了一个 -W 选项。该选项的作用是让SSH服务器打开到某一特定IP/端口的TCP连接,并将标准输入输出与该连接绑定,这与 nc(1) 类似。此功能最早在2010年由OpenSSH 5.4引入。
传统上,OpenSSH支持一个名为 ProxyCommand 的选项,该选项可以让系统在连接时在本地运行一个命令。故而,我们可以把 ProxyCommand 写作 ssh -W %h:%p username@<跳板服务器> 来告诉 ssh(1)
在连接服务器时,首先连接 username@<跳板服务器> 并用其作为代理服务器来提供服务,如下图所示。
+-------+ +-------+ +--------------------+
| 客户机 |------>| 跳板机 |------>| 另一网络上的SSH服务器 |
+-------+ +-------+ +--------------------+不过,对于比较复杂的网络来说,有可能需要使用多层跳板。ProxyCommand 仍然可以满足此需求,但写起来会复杂不少。考虑到使用 ssh -W 是一种常见情形,在OpenSSH 7.5中引入了一个新的选项
ProxyJump,它可以直接指定多个跳板机,并在每一跳使用不同的用户名/端口来进行连接。由于该功能大致上时 ProxyCommand 的子集,因此它和 ProxyCommand 同时在配置中出现时,只有后出现的那一个生效。
根据条件选择是否使用跳板
使用跳板机可能并非在所有情况下都适合,例如如果跳板机完成的功能是接受IPv4的SSH连接请求,并提供到IPv6网络的连接服务,那么在一个有IPv6服务的地方可能就无所谓是否使用跳板机了。
OpenSSH的 Host 配置只支持做模式匹配(例如: *.example.com)而无法灵活地判断当前网络环境。自然,我们可以使用脚本去让系统使用不同的 ~/.ssh/config 文件,但这种外科手术式的做法并不美观。OpenSSH还提供了一个 Match 配置,除了模式匹配之外,它还支持使用一个可执行文件来判断当前主机是否匹配,这样就可以做更加灵活的判断了。
下面是一个简单的此类脚本,其原理是通过调用某个支持 GET 方法的API来判断是否可以直接连通内网并据此返回是否使用跳板的结果:
| |
或者,下面的脚本可以判断是否能够连上IPv6网络:
| |
与之对应的 ssh_config 或 ~/.ssh/config 配置如下:
Match host 10.*,*.internal.example.com exec "/usr/local/bin/need_proxy %h"
ProxyJump trampoline.example.com其中 trampoline.example.com 是一台在Internet上可达的SSH服务器作为跳板。第一个脚本不需要 %h 参数,其他可以使用的参数请参见 ssh_config(5)。