一 为什么使用SSH代理?
我们访问局域网内的主机时,一般的做法是将要访问的服务的端口映射到防火墙(公网IP)上的某一个端口,然后通过访问公网IP:端口的形式访问服务,这也就直接将服务暴露在公网上了,进行一些端口扫描很容易发掘服务器开放了哪些端口。
下面的示例就是阿里云上的一台负载均衡服务器,为了从公司内部访问阿里云ECS主机上部署的服务,在负载均衡上开放了很多的端口。
docker@k8s01:~$ nmap -p1-65535 147.192.141.240
Starting Nmap 7.60 ( https://nmap.org ) at 2019-04-08 01:58 UTC
Nmap scan report for 147.192.141.240
Host is up (0.048s latency).
Not shown: 65522 filtered ports
PORT STATE SERVICE
80/tcp open http
443/tcp open https
1883/tcp open mqtt
2883/tcp open ndnp
4242/tcp open vrml-multi-use
4321/tcp open rwhois
5000/tcp open upnp
8443/tcp closed https-alt
9443/tcp open tungsten-https
15672/tcp open unknown
30258/tcp open unknown
31928/tcp open unknown
32195/tcp open unknown
Nmap done: 1 IP address (1 host up) scanned in 120.11 seconds
可见一些常用服务很容易被识别出来,例如:
- 5000端口(Docker Registry的服务端口)
- 4242端口:opentsdb默认使用的端口
- 15672:RabbitMQ的管理页面的端口
- xxx22的端口一般是SSH服务端口等等
通过简单的猜测和尝试,就可能导致服务器的信息泄露从而被黑客攻击,导致某些服务不可用,严重的话还可能导致利用某些服务的漏洞获取到服务器的root权限。
为了消除这些安全问题,最好的做法就是不在公网上暴露任何端口,但是这样带来的问题是,从公司内网如何正常访问这些服务呢?
答案就是SSH反向代理。
二 什么是SSH反向代理?
先说说什么是代理,源服务器由于各种原因无法访问目标服务器提供的服务,但是存在一个agent服务器,源服务器可以访问它,它可以访问目标服务器,那么源服务器的消息发给他,它在把请求转发给目标服务器,就间接的实现了源服务器访问目标服务器的目的。
这就是代理,也是一般所说的正向代理,正向代理一般是代理客户端(源服务器,信息的请求者)。这时候,在公网上发送的信息的请求者就是代理服务器的身份,而不是真正客户端的身份。好处显而易见,隐藏客户端的身份。
那什么是反向代理呢?
百度百科:当一个代理服务器能够代理外部网络上的主机,访问内部网络时,这种代理服务的方式称为反向代理服务。
这句话不太好理解,应该改一改:“当一个代理服务器能够代理外部网络上的主机,使得内部网络可以访问时(不通过公网IP),这种代理服务的方式称为反向代理服务。”
例如下面的场景:公司局域网内的服务器(例如172.16.1.1)可以访问公网,公网无法访问它,如果不在公司的出口防火墙上暴露端口,那么在你的家里(192.168.0.100)(具有一个出口公网IP的局域网,已经将客户机(192.168.0.100的端口通过NAT(家用路由器就有这个功能))映射到出口公网IP的一个端口上),这时候,公司局域网的服务器是可以访问家用出口公网IP的,这时候,通过一个反向代理,将服务器的服务端口代理到家用出口公网IP上的绑定端口上,这时候,在你家里,就可以像访问本机服务一样访问公司内部服务器提供的服务了。
下面一张图来说明:
反向代理,将服务器的端口代理到外部网络中,在外部网络中可以直接访问,隐藏了真实的服务端,在外部网络中访问时候,就像访问同一网络中的服务一样。
上面的图中,通将MySQL的3306端口通过SSH反向代理到家庭局域网的主机上,在家庭主机上,可以像访问本机服务一样访问公司内部的MySQL服务。
三 SSH反向代理的好处是什么?
SSH会话通过建立一个加密的通道,在数据入口(SSH客户端)处进行加密,在出口(SSH服务端)进行解密,实现了比较安全的会话机制。
SSH还支持转发TCP、UDP的消息,这样其他依赖于TCP、UDP的服务均可以利用SSH代理来实现转发访问。
即使我们使用不安全的协议,例如FTP、TELNET等明文通讯协议,也不怕信息泄露,因为这一切都是发生在SSH建立起的加密隧道中的,无法被轻易窃取。
四 SSH反向代理的原理是什么?
端口转发。
将某个端口接收到的请求转发到指定的端口上。
SSH反向代理时,服务端主动发起SSH连接到代理服务器,将代理服务器指定端口接受到的请求通过SSH隧道转发到服务端的指定的端口上。对于原有的通讯是透明的,SSH相当于高速公路,不管你是什么车,上高速之前跟下高速之后都是一样的,告诉公路保证了你的告诉通行。
五 实际案例详解
公司在阿里云主机上购买了多台ECS主机部署了微服务,某些服务需要在公司内网进行访问。但是在防火墙了打个洞(开个端口)又带来了极大的安全风险。所以决定利用SSH的安全特性采用SSH反向代理的形式访问服务。
ECS主机可以访问公网,公网不可以访问ECS主机。ECS主机的内网IP是192.168.0.26.
公司内部有一个机器,将SSH服务的22端口映射到了公司出口公网IP的12022端口上,因此ECS主机可以SSH到这台主机。
这时候通过下面的命令在ECS主机上启动SSH反向代理:
ssh -NfR 4242:localhost:32541 root@123.139.238.155 -p10022
上面的命令,是将ECS主机上的32541端口与远端(公司内网机器)的4242端口绑定起来。这样发送给公司内部机器4242端口的请求都将转发到服务端的32541端口上。
但是这样子,4242端口只是监听在127.0.0.1上,显然我们还需要从公司内部的其他机器访问,所以这个端口需要监听在内网IP上,这时候又利用到了SSH端口转发的功能:
ssh -N -f -L 10.0.0.56:4242:127.0.0.1:4242 root@10.0.0.56
上面的命令是将10.0.0.56:4242接收到的请求转发哦到本机的127.0.0.1:4242端口上,4242端口恰好是SSH反向代理监听的端口,随后请求就会被转发到ECS主机上的32541端口,这样在公司内部就实现了访问ECS主机服务。同时特避免了在防火墙上打洞。
这样子如果ECS主机上的SSH进程停止了,那么从公司内部就无法访问了,可以利用autossh的自动重连机制来避免这种情况。
在ECS主机上安装autossh程序后,通过下面的命令启动:
autossh -M 7281 -fCNR 3306:localhost:3306 root@48.59.69.26
-M参数理解为心跳即可。当心跳不通时,就会重连。当然也需要端口再转发下。否则只能从127.0.0.1访问。
再将上面的命令放入脚本中,开机启动即可。就能够实现从公司内部稳定持续访问ECS主机服务了。
SSH参数说明:
- -N:指定这个SSH连接只进行端口消息转发,不执行任何SSH远程命令;
- -L:指定本地监听的地址和端口;
- -f: 这个SSH会话放入后台运行,不加这个参数的话,当退出当前SSH -L指定的终端时,端口转发进程就结束了,端口转发送也就结束了。所以务必要加上-f参数。