Linux利用隧道协议连接私有网络

0x00 前言

最近在搬砖的过程中,碰到了一个问题需要解决:公司的系统服务需要调用第三方平台的接口,而该平台的接口是无法直接调用的,必须拨 SSLVPN 连接到第三方平台的私有网络,然后才能调用他们的接口。

但公司的业务主要基于 soa 架构,为所有调用者服务都装 sslvpn 是不可行的,更重要的是,公司内部使用的 k8s 集群运行的服务,容器网络和 sslvpn 同时运行会给系统带来很大的复杂性,所以需要找个其他办法。

0x01 内网测试

网络情况

这里简单的描述下内部网络情况:

  1. 公司内网网段: 192.168.100.0/24
  2. VPN 的虚拟网段: 172.16.0.0/24
  3. sslvpn 前置机的私有网络 IP: 172.16.0.10
  4. sslvpn 前置机的内网 IP: 192.168.100.20
  5. k8s node的 IP: 192.168.100.10
  6. 被调用服务 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 节点
    1. 配置 vpn 前置机为 vpn 网段的下一跳路由: ip route add 172.16.0.0/24 via 192.168.100.20 dev eth0
  • sslvpn 前置机
    1. 开启 Linux IP Forward: echo 1 > /proc/sys/net/ipv4/ip_forward
    2. 使用 iptables 做 NAT,让从 k8s node发过来的包通过 tun0 设备发到远端被调用服务 IP:iptables -t nat -I POSTROUTING -s 192.168.100.10 -o tun0 -j MASQUERADE
    3. 保存 iptables: service iptables save

在进行完以上配置后,进入到 k8s node 上的 Docker 容器,然后 curl 172.16.0.138:8080模拟调用接口操作,Response正常,完美!

0x02 线上测试

本来以为内网测试完就正常了,没想到线上环境还有个坑在等着我。线上生产环境我们用的是阿里云,由于之前买的 ECS 一直都是用的经典网络,而经典网络只保证三层通信,且k8s node 与 前置机之间隔着好几跳,那么直接配置下一条路由行不通了...坑啊

线上网络介绍

  1. VPN 的虚拟网段: 172.16.0.0/24
  2. sslvpn 前置机的私有网络 IP: 172.16.0.10
  3. sslvpn 前置机的阿里云内网 IP: 10.24.0.20/22
  4. k8s node的阿里云内网 IP: 10.56.0.10/22
  5. 被调用服务 IP: 172.16.0.138
  6. 点对点 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 了

  1. 分别在k8s node机器和vpn前置机机器上创建 tun 设备并配置 IP,并配置静态路由
    • k8s node:
      1. 在k8s节点上创建 tun 设备: ip tunnel add vpnnic mode ipip remote 10.24.0.20 local 10.56.0.10
      2. 给 vpnnic 配置点对点IP地址: ifconfig vpnnic 192.168.10.1 netmask 255.255.255.0
      3. 配置前置机为下一跳: ip route add 172.16.0.0/24 via 192.168.10.2 dev vpnnic
    • vpn前置机:
      1. 在前置机上创建 tun 设备: ip tunnel add vpnnic mode ipip remote 10.56.0.10 local 10.56.0.10
      2. 给 vpnnic 配置点对点IP地址: ifconfig vpnnic 192.168.10.2 netmask 255.255.255.0
  2. 此时,在k8s node上 ping -c3 192.168.10.2 如果是通的,则说明 IPIP 配置成功了
  3. 接下来分别在vpn前置机上拨上vpn,并开启 ip_forward 和 iptables 即可
  • sslvpn 前置机
    1. 开启 Linux ip_forward: echo 1 > /proc/sys/net/ipv4/ip_forward
    2. 使用 iptables 做 NAT,让从 k8s node发过来的包通过 tun0 设备发到远端被调用服务 IP:iptables -t nat -I POSTROUTING -s 192.168.10.1 -o tun0 -j MASQUERADE
    3. 保存 iptables: service iptables save

在进行完以上配置后,我进入到 k8s node 上的 Docker 容器,然后 curl 172.16.0.138:8080模拟调用接口操作,成功发送请求。终于大功告成啦!

0x03 小结

对于这个操作有三点要注意:

  1. 首先配置点对点的虚拟设备
  2. 然后配置路由和 iptables
  3. 上面的配置都是临时的,想要永久有效需要写入配置文件
  4. 由于是点对点的,如果调用者很多的话,各自建立 tun 设备工作量较大,可以考虑一对多的协议