前几篇有关ssh的文章,我们只是介绍了ssh的登录功能。其实ssh功能不只是这些,这篇文章我们来介绍下有关ssh隧道的功能。
ssh隧道也叫ssh端口转发,或者叫ssh tunnel,这些都是说的是ssh隧道功能。在此,我们统称为ssh隧道。
ssh隧道分为正向隧道和反向隧道,在实际工作中我们可以根据需要来随其分别使用。
下面开始对正向和反向隧道分别介绍下,由于使用平台的不同,我们分为Linux和windows平台。
一、ssh正向隧道
什么是ssh正向隧道?
就是client连上server后,然后把server能访问的IP地址和端口(当然也包括server自己)镜像到client的端口上。
在平时工作中,正向隧道是我们使用最多的一种方式。
ssh正向隧道的命令如下:
ssh –L clientC_IP:clientC_port:serverB_IP:serverB_port -p serverA_sshport [email protected]_IP
上述命令的意思是在客户端clientC上通过ssh连接服务器serverA,然后再把服务器serverB上的serverB_port端口映射到客户端clientC的clientC_port端口。
也就是说如果我们现在连接clientC的clientC_port端口的话,就是连接服务器serverB上的serverB_port的端口。
上述命令的使用场景一般是,客户端clientC在公司内部使用的是内网IP,而服务器serverA和serverB在IDC机房或者在云服务器商那边。服务器serverA有公网IP能与客户端clientC正常通信,而服务器serverB没有公网IP不能与客户端clientC直接通信,但是服务器serverA和服务器serverB是通过内网进行通信的。现在要求客户端clientC访问serverB的相关端口。
客户端clientC、服务器serverA与服务器serverB,通信示意图如下:
要达到上述要求,我们就可以通过ssh正向隧道的功能。为了看出实际的效果,在此以连接后端的mysql数据库为例。具体配置根据操作平台的不同,分别介绍如下。
1.1 Linux下配置ssh正向隧道
在Linux下配置ssh正向隧道比较简单,直接使用上述命令即可。如下:
ssh -g -f -NL 192.168.7.7:44010:10.66.115.185:3306 -i /home/ilanni/id_dsa_1024_0601 [email protected]
ps -ef |grep 44010
上述命令的意思是在192.168.7.7这台机器通过ssh方式连接115.159.39.187这台服务器,然后把10.66.115.185这台服务器的3306端口也即是mysql端口映射为192.168.7.7的44010端口。
现在在局域网内,只要我们连接192.168.7.7的44010端口,其实就在连接10.66.115.185的3306端口。
现在我们来测试下,是否可以连接成功。在与192.168.7.7同一个LAN中的任意一台能连接192.168.7.7的44010端口的机器上,使用mysql的客户端,如下:
注意:IP地址和端口一定要填写为192.168.7.7和44010,而用户名和密码只需要填写mysql数据库对应的用户名和密码即可。
通过上面两张图,我们可以看到连接192.168.7.7的44010端口,确实就是连接的10.66.115.185的3306端口。也即是在公司内部连接IDC内的后端数据库。
如果公司内部对访问后端数据库有权限要求的话,我们可以在服务器serverB(mysql数据库10.66.115.185)上只允许服务器serverA(115.159.39.187)访问服务器serverB(10.66.115.185)的3306端口通过相关的安全策略比如IPtables或者mysql用户授权对服务器serverA(115.159.39.187)。
然后再在服务器serverA(115.159.39.187)也即是192.168.7.7上通过IPtables配置相关的内网机器能访问44010端口。
通过这样的操作就可以在公司内部达到控制后端mysql数据库的权限控制。
1.2 windows下配置ssh正向隧道
在windows下配置ssh正向隧道,需要我们使用ssh相关的客户端软件。在此我使用的xshell,当然你也可以使用putty等之类的软件。
打开xshell,新建一个连接到serverA(115.159.39.187)的会话,如下:
注意:这个地方填写的是serverA的IP地址。
在这填写的用户就是serverA的用户。
这张图很重要,因为是ssh正向隧道,所以在此类型里面选择的是Local。
源主机填写的是clientC的IP地址(在哪台机器就填写哪台机器的IP),侦听端口就是serverB的serverB_Port端口映射到clientC上的端口。注意侦听端口可以随便自定义。
目标主机填写的是serverB的IP地址,目标端口填写的是serverB_Port端口号。
以上配置完毕后,我们在本机192.168.1.180上连接看看是否可以正确连接serverB的serverB_Port端口。如下:
通过以上几张图,我们可以很明显的看出,以上配置是正确的。
注意:windows下配置ssh正向隧道和Linux还是有所不同的。windows正确配置后,如果要使用隧道的话。xshell连接serverA的会话不能关闭。也就是说clientC连接serverA的ssh会话要一直开着,而且即使正常连接后,该ssh会话也是一直存在的。如下:
二、ssh反向隧道
什么是ssh反向隧道?
就是client连上server后,然后把client能访问的IP地址和端口(也包括client自己)镜像到server的端口上。
ssh反向隧道使用场景,比如你的客户端在内网,在外网是无法直接访问到的,这时用反向隧道打通一条连接,就可以从外网通过这条隧道进来了。
ssh反向隧道的命令如下:
ssh –R serverA_IP:serverA_port:clientC_IP:clientC_port -p serverA_sshport [email protected]_IP
上述命令的意思是在客户端clientC(或者clientC所在的LAN中的任意一台能连接clientC_port的机器)上通过ssh连接服务器serverA,然后再把客户端clientC的clientC_port端口映射到服务器serverA上的serverA_port端口。
也就是说如果我们现在在服务器serverB上连接服务器serverA上的serverA_port端口的话,就是连接clientC的clientC_port端口。数据流向,如下图示:
注意:建议修改serverA服务器的ssh配置文件sshd_config,添加GatewayPorts yes。然后重启ssh服务。
这样ssh反向隧道建立成功后,在serverA服务器监听的端口为serverA服务器的所有地址。如下:
如果不这样修改的话,在serverA服务器监听的端口会为127.0.0.1。如下:
2.1 Linux下配置ssh反向隧道
在Linux下配置ssh反向隧道比较简单,直接使用上述命令即可。如下:
ssh -g -f -NR 115.159.39.187:44010:192.168.5.174:3306 -i /home/ilanni/id_dsa_1024_0601 [email protected]
ps -ef |grep 44010
上述命令的意思是在192.168.5.174这台机器通过ssh方式连接115.159.39.187这台服务器,然后把192.168.5.174这台服务器的3306端口也即是mysql端口在115.159.39.187服务器上映射为44010端口。
也就是说现在在公网上,只要我们连接115.159.39.187的44010端口,其实就是在连接192.168.5.174的3306端口。
为了能很实际的效果,现在我们在192.168.5.174上新建ilanni这个一个数据库。如下:
mysql -uroot -p123456
create database ilanni;
show databases;
现在我们登录到115.159.39.187服务器上进行查看。如下:
netstat -tunlp
通过上图,我们可以看到115.159.39.187服务器上确实在监听44010端口。
下面我们在115.159.39.187服务器上来连接下192.168.5.4的3306端口。如下:
mysql -h127.0.0.1 -P44010 -uroot -p123456
show databases;
通过上图,我们可以很明显的看到在115.159.39.187服务器上连接44010端口确实连接到了192.168.5.4的3306端口。
2.2 windows下配置ssh反向隧道
在windows下配置ssh反向隧道,和配置ssh正向隧道基本一样也需要使用ssh相关的客户端软件,在此我使用的还是xshell。
注意:ssh反向隧道,我们可以在与clientC同一LAN的任意一台能访问clientC_Port端口的机器上进行。
打开xshell,新建一个连接到serverA(115.159.39.187)的会话,如下:
注意:这个地方填写的是serverA的IP地址。
在这填写的用户就是serverA的用户。
这张图很重要,因为是ssh反向隧道,所以在此类型里面选择的是Remote。
源主机填写的是serverA的IP地址,侦听端口就是clientC的clientC_Port端口映射到serverA上的端口。注意侦听端口可以随便自定义。
目标主机填写的是clientC的IP地址,目标端口填写的是clientC_Port端口号。
现在我们登录到115.159.39.187服务器上进行查看。如下:
netstat -tunlp
通过上图,我们可以看到115.159.39.187服务器上确实在监听44010端口。
下面我们在115.159.39.187服务器上来连接下192.168.5.4的3306端口。如下:
mysql -h127.0.0.1 -P44010 -uroot -p123456
show databases;
通过上图,我们可以很明显的看到在115.159.39.187服务器上连接44010端口确实连接到了192.168.5.4的3306端口。
三、实际应用
以上介绍了ssh正反向隧道详细使用方法,以mysql的3306端口为例子。下面我就结合实际的工作需求,介绍下ssh隧道的其他使用场合。
3.1 远程桌面
ssh隧道也是代理可以在windows以及Linux的远程桌面的,这种场合一般是在这样的场合下使用。
公司对外提供v*n服务,但是该v*n服务器在网络DMZ防火区。v*n服务器可以访问lan内的机器,但是lan内的机器不能访问v*n服务器。结构图,如下:
v*n客户端连接进来后,我们只需要在DMZ区的服务器上,建议一条ssh正向隧道即可连接隧道指定的lan机器。
如下:
ssh -g -f -N -L 7002:192.168.5.140:3389 [email protected]
上述命令的意思是把192.168.5.140的3389端口映射到192.168.7.7的7002端口。也就说我们现在在v*n客户端连接192.168.7.7的7002端口其实就是连接192.168.5.140的3389端口。如下:
通过上图,我们可以很明显的看出ssh正向隧道已经代理了远程桌面。
3.2 nginx访问
现在公司线上云服务器上有一台业务serverB,前端使用nginx做反向代理,后端使用的是nodejs,serverB只对云服务器提供访问。
目前要求在公司内部也可以访问serverB上的nginx,并且不是公司内部所有人员都可以访问,只有指定的个别人才能有权限访问。
分析:如果要使公司内部访问serverB上的nginx,我们只需要在serverB开放对公司公网的IP访问权限即可。
但是如果还要控制访问权限的话,这个就需要借助ssh正向隧道来实现了。
在云服务器上开放一台serverA,serverA能访问serverB的nginx(该访问权限的控制可以通过nginx或者iptables进行控制),而serverA又对公司的公网IP开放SSH端口。
然后在公司内网的任意一台lanC上,做一条ssh正向隧道。该隧道把serverB的nginx端口映射到serverC上一个PortC端口。
此时我们再在lanC上对PortC端口的访问权限进行控制(该访问权限的控制可以通过nginx或者iptables进行控制)即可达到上述要求。
现在lanC上使用如下命令:
ssh -g -f -NL 192.168.5.4:8080:10.104.13.164:80 -i id_dsa_1024_0601 [email protected]
ps -ef |grep 8080
上述命令的意思是在192.168.5.4上通过115.159.44.136这台服务器把10.105.12.163这台服务器的80端口映射为192.168.5.4的8080端口。
lanC的nginx配置如下:
server {
listen 80;
server_name 192.168.5.4;
allow 127.0.0.1;
allow 192.168.5.140;
deny all;
location / {
proxy_pass http://192.168.5.4:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_connect_timeout 200;
proxy_send_timeout 200;
proxy_read_timeout 600;
}
}
上述nginx配置的意思是允许192.168.5.140这台机器访问192.168.5.4的80端口,而192.168.5.4会把访问192.168.5.4:80的请求交给192.168.5.4:8080进行处理。
这样就达到了前文的要求。
现在在192.168.5.140*问192.168.5.4的80端口。如下:
通过上图,我们可以很明显的看出ssh正向隧道已经可以代理nginx。
3.3 ssh多级隧道跳转
ssh多级隧道跳转看起来感觉很难,其实如果细细拆分的话很简单的。
下面有一个实际的要求,我们来分析下。
情况介绍:
serverC只允许serverB连接serverC的1001端口其他端口不允许serverB连接,而serverB只允许serverA能连接serverB的22端口,不能连接serverC的1001端口,同时serverA是只对公网开放的ssh的22端口其他端口不对公网开放。
要求:
现在要求lan内部的clientC能连接serverC的1001端口。
分析:
如果我们直接serverC的1001端口那是不可能的,因为安全策略有限制。那么我们可以通过ssh正向隧道来解决此问题。
首先在serverA上通过serverB做一条ssh正向隧道把serverC的1001端口映射为serverA的1002端口。
即访问serverA的1002端口就是访问serverC的1001端口。
因为serverA的1002端口不对公网开放,那么为了能访问serverA的1002端口,我们可以在clientC通过serverA再做一条ssh正向隧道把serverA的1002端口映射为clientC的1003端口。
也就是说此时我们连接clientC的1003端口其实就是在连接serverC的1001端口。
以上ssh多级隧道跳转的原理介绍清楚了,在次就不在进行演示。如果有哪位不懂的可以多多理解理解上面的描述。