利用SSH隧道访问局域网

SSH(Secure SHell)是一种基于加密算法的网络安全协议, 其在TCP/IP协议的基础上通过非对称公钥算法对用户身份进行验证. SSH在网络中有广泛的应用, 比如平常在远程登录时就会用到SSH, Github的代码仓库提交也会基于SSH协议来验证提交者的合法性, 而对常年生活在局域网内的人来说, SSH更多的用途则是搭建穿越防火墙的VPN实现网络自由.

一台服务器如果有公共域名或者IP地址, 只需要事先将客户端的公钥放到服务器上就可以正常登录, 但如果服务器本身位于防火墙之外(比如某个端口被禁)或者位于NAT(Network Address Translation)网关之后, 这个方法就不起作用了. 用过VPN的同志应该比较清楚, 穿透防火墙或者某个局域网的NAT网关, 一般要用到SSH隧道技术(SSH tunneling);SSH隧道技术也被称为端口转发(port forwarding).简单来说, 建立SSH隧道大致有两个流程:

  • 由位于局域网的设备A向服务器PC发起SSH连接, 建立一个安全加密的通信通道, 并基于该通道监听某个特定的端口
  • 接着, 服务器基于已有的加密通道再建立一个SSH通信链路,基于这个通道服务器就可以登录到大屏, 执行交互指令

SSH login

SSH隧道技术的端口转发具体说有两种, 一种叫本地端口转发(local port forwarding), 就是在客户端做端口转发;一种叫远端端口转发(remote port forwarding), 就是在服务端做端口的数据转发, 这篇文章用到的技术是后一种.

这里就来看看如何通过SSH隧道技术来实现对局域网内某个服务器的登录: 局域网内有一台设备A(服务端), 只有私有IP地址, 通过NAT网关访问外部网络, 设备B(客户端)是外部网络的一个PC, 现在要通过该PC(设备B)正常登录到设备A.

实现SSH隧道功能

在开启SSH隧道功能之前, 确保客户端/服务器都正常配置了ssh(SSH的客户端程序)/sshd(SSH守护进程):

  • ssh: ssh登录的客户端, 负责发起ssh登录请求, 其配置一般放在/etc/ssh/ssh_config
  • sshd: sshd是服务端的守护进程, 负责监听来自客户端的请求, 其配置放在/etc/ssh/sshd_config

    为了确保ssh可以正常进行端口转发, 需要打开AllowTcpForwarding:

  • 设置AllowTcpForwardingyes, 确保能够使用端口转发功能

另外SSH密钥交换时要用到主机的密钥(host key), 可以通过ssh-keygen产生, 对于Ubuntu系统来说, 主机密钥一般放在/etc/ssh目录下.

为了避免每次ssh登录都要输入密码, 可以事先分别在客户端/服务器产生一个rsa密钥对, 并将公钥放到服务器/客户端的/.ssh/authorized_keys中保存下来, 并在执行ssh指令时指定对应的私钥文件, 这样身份验证就会在密钥验证阶段完成无需再输入用户密码了.

启动sshd

配置完成后, 如果没有sshd进程, 需要在设备A(服务端)/设备B(用户端)都启动sshd:

1
sshd -ddd -h /etc/ssh/ssh_host_rsa_key -f /etc/ssh/sshd_config

其中参数-ddd用于输出调试信息, -h指定host密钥文件, -f指定sshd的配置;启动完成后, 设备就可以正常收到来其他ssh客户端的请求了.

启动ssh远程登录

在大屏输入如下指令, 尝试与设备A(客户端)建立SSH链接:

1
ssh -vvv -TN -i <identity_file> -R 8989:localhost:22 user_name@remote_host

-vvv参数用于输出debug信息, -TN告诉ssh在登录后不要开启终端执行指令而是监听某个指定的端口, -i制定身份验证的密钥文件目录, 参数-R指定了远端转发端口的规则: 将来自远端8989的数据都转发到本地的22端口; 执行该命令后, 身份验证通过, 可能会输入服务器密码, 然后我们就可以看到ssh会一直在监听8989这个端口, 接着在设备A(服务器)输入指令:

1
ssh -vvv -i <identity_file>  -p 8989 root@localhost

身份认证完成后, 就可以看到一个输入shell指令的命令窗口, 就算登录完成了.

参考资料

0%