Linux利用隧道协议连接私有网络
0x00 前言
最近在搬砖的过程中,碰到了一个问题需要解决:公司的系统服务需要调用第三方平台的接口,而该平台的接口是无法直接调用的,必须拨 SSLVPN 连接到第三方平台的私有网络,然后才能调用他们的接口。
但公司的业务主要基于 soa 架构,为所有调用者服务都装 sslvpn 是不可行的,更重要的是,公司内部使用的 k8s 集群运行的服务,容器网络和 sslvpn 同时运行会给系统带来很大的复杂性,所以需要找个其他办法。
0x01 内网测试
网络情况
这里简单的描述下内部网络情况:
- 公司内网网段: 192.168.100.0/24
- VPN 的虚拟网段: 172.16.0.0/24
- sslvpn 前置机的私有网络 IP: 172.16.0.10
- sslvpn 前置机的内网 IP: 192.168.100.20
- k8s node的 IP: 192.168.100.10
- 被调用服务 IP: 172.16.0.138
解决方法
为了解决这个问题,首先我在公司内网的 k8s 集群上进行测试。一般情况下,对于这种需要通过 VPN 作为接入点给内部服务使用的情况,应该考虑单独使用前置机。所以我开了一台 CentOS 虚拟机,并在上面安装了 sslvpn 的客户端,并成功了拨上了 VPN。
同时,我发现 sslvpn 为前置机的网络生成了一个虚拟网卡,名字叫做 tun0 ,并为其分配了 IP 为 172.16.0.10/24,这也是为什么 sslvpn 作为一个应用层的 VPN 类型,却也可以让三层网络互通。原因就是 tun0 设备上收到的包都会被上层协议封装,并通过 sslvpn 发送到远端并解封装,从而实现VPN 网络三层互通。
那接下来就好办了,我只要进行如下配置即可让 k8s node 上的容器可以访问到 172.16.0.138 了
- k8s 节点
- 配置 vpn 前置机为 vpn 网段的下一跳路由:
ip route add 172.16.0.0/24 via 192.168.100.20 dev eth0
- 配置 vpn 前置机为 vpn 网段的下一跳路由:
- sslvpn 前置机
- 开启 Linux IP Forward:
echo 1 > /proc/sys/net/ipv4/ip_forward
- 使用 iptables 做 NAT,让从 k8s node发过来的包通过 tun0 设备发到远端被调用服务 IP:
iptables -t nat -I POSTROUTING -s 192.168.100.10 -o tun0 -j MASQUERADE
- 保存 iptables:
service iptables save
- 开启 Linux IP Forward:
在进行完以上配置后,进入到 k8s node 上的 Docker 容器,然后 curl 172.16.0.138:8080
模拟调用接口操作,Response正常,完美!
0x02 线上测试
本来以为内网测试完就正常了,没想到线上环境还有个坑在等着我。线上生产环境我们用的是阿里云,由于之前买的 ECS 一直都是用的经典网络,而经典网络只保证三层通信,且k8s node 与 前置机之间隔着好几跳,那么直接配置下一条路由行不通了...坑啊
线上网络介绍
- VPN 的虚拟网段: 172.16.0.0/24
- sslvpn 前置机的私有网络 IP: 172.16.0.10
- sslvpn 前置机的阿里云内网 IP: 10.24.0.20/22
- k8s node的阿里云内网 IP: 10.56.0.10/22
- 被调用服务 IP: 172.16.0.138
- 点对点 IP: 192.168.10.1/24,192.168.10.2/24
解决方法
我想既然 k8s node 和前置机不在同一子网,那我给你们单独打条隧道还不行吗?这样 k8s node 就又可以将vpn 前置机设置为下一跳啦。
说干就干,既然两台机器三层互通,那么我就考虑用三层网络的点对点协议了。三层的点对点协议有很多,如 ipip,GRE,IPSec等等。我这里要求也不复杂,所以我就直接用最简单方便的 ipip 配置了
建立点对点隧道
隧道协议大致原理如上图所示,总的来说就是在点对点的 IP 包外面再包上一层 IP 包。步骤如下:
那接下来就好办了,我只要进行如下配置即可让 k8s node 上的容器可以访问到 172.16.0.138 了
- 分别在k8s node机器和vpn前置机机器上创建 tun 设备并配置 IP,并配置静态路由
- k8s node:
- 在k8s节点上创建 tun 设备:
ip tunnel add vpnnic mode ipip remote 10.24.0.20 local 10.56.0.10
- 给 vpnnic 配置点对点IP地址:
ifconfig vpnnic 192.168.10.1 netmask 255.255.255.0
- 配置前置机为下一跳:
ip route add 172.16.0.0/24 via 192.168.10.2 dev vpnnic
- 在k8s节点上创建 tun 设备:
- vpn前置机:
- 在前置机上创建 tun 设备:
ip tunnel add vpnnic mode ipip remote 10.56.0.10 local 10.56.0.10
- 给 vpnnic 配置点对点IP地址:
ifconfig vpnnic 192.168.10.2 netmask 255.255.255.0
- 在前置机上创建 tun 设备:
- k8s node:
- 此时,在k8s node上
ping -c3 192.168.10.2
如果是通的,则说明 IPIP 配置成功了 - 接下来分别在vpn前置机上拨上vpn,并开启 ip_forward 和 iptables 即可
- sslvpn 前置机
- 开启 Linux ip_forward:
echo 1 > /proc/sys/net/ipv4/ip_forward
- 使用 iptables 做 NAT,让从 k8s node发过来的包通过 tun0 设备发到远端被调用服务 IP:
iptables -t nat -I POSTROUTING -s 192.168.10.1 -o tun0 -j MASQUERADE
- 保存 iptables:
service iptables save
- 开启 Linux ip_forward:
在进行完以上配置后,我进入到 k8s node 上的 Docker 容器,然后 curl 172.16.0.138:8080
模拟调用接口操作,成功发送请求。终于大功告成啦!
0x03 小结
对于这个操作有三点要注意:
- 首先配置点对点的虚拟设备
- 然后配置路由和 iptables
- 上面的配置都是临时的,想要永久有效需要写入配置文件
- 由于是点对点的,如果调用者很多的话,各自建立 tun 设备工作量较大,可以考虑一对多的协议