本文介绍如何使用strongSwan作为本地网关,实现云上和云下的网络互通。
strongSwan是一个开源、基于IPsec的VPN解决方案,配置简单,可部署在主流的Linux发行版,快速地与阿里云建立IPsec-VPN连接。
场景示例
以下图场景为例,您可以在本地网关设备上部署strongSwan软件(下文简称为“strongSwan设备”),与阿里云建立双隧道模式的IPsec-VPN连接,实现云上云下网络互通。
IP地址规划
本地IDC侧
私网网段:10.0.0.0/16
strongSwan设备
网卡eth0: 10.0.0.1,NAT映射公网出口1:1.1.XX.XX
(可选)网卡eth1: 10.0.0.2,NAT映射公网出口2: 2.2.XX.XX
说明非NAT场景,请参见“strongSwan设备网卡绑定了公网IP地址,如何配置?”。
无论您的设备有1个公网出口(单出口),还是有2个公网出口(双出口),均可与阿里云建立双隧道模式的IPsec-VPN连接,本文会分别给出示例。
阿里云侧
VPC网段:172.16.0.0/16
交换机1网段:172.16.1.0/24
交换机2网段:172.16.2.0/24
VPN网关
IPsec地址1: 3.3.XX.XX
IPsec地址2: 4.4.XX.XX
说明创建VPN网关实例后,系统会自动为VPN网关实例分配两个IPsec地址。
VPN参数配置规划
本文的2条隧道使用相同的示例值。注意每条隧道下,strongSwan设备侧和阿里云侧的配置要保持相同。
预共享密钥:ChangeMe***
IKE配置
IKE版本:ikev2
协商模式:main
加密算法:aes
认证算法:sha1
DH分组:group2
SA生存周期(秒):86400
IPsec配置:
加密算法:aes
认证算法:sha1
DH分组:group2
SA生存周期(秒):86400
阿里云侧的准备工作
配置strongSwan设备之前,请先根据场景示例中的规划,在阿里云侧完成创建VPN网关实例、创建用户网关、创建IPsec连接、配置VPN网关路由的步骤。具体操作,请参见建立VPC到本地数据中心的连接(双隧道模式)。
根据strongSwan设备的公网出口数量,阿里云侧的配置有如下区别:
单出口
用户网关:因为只有1个公网出口IP,只需创建1个用户网关。
IPsec连接:
每条隧道的路由模式选择感兴趣流模式。
本端网段填写阿里云侧VPC的网段 172.16.0.0/16
对端网段填写本地IDC侧的私网网段 10.0.0.0/16
用户网关选择同1个。
双出口
用户网关:因为有2个公网出口IP,需要对应创建2个用户网关。
IPsec连接:
选择路由模式时,2条隧道都选择目的路由模式。
选择用户网关时,隧道1对应公网出口1,隧道2对应公网出口2。
开始配置strongSwan设备
下文步骤以运行“CentOS Stream 9 64位操作系统”的strongSwan设备为例。其他操作系统,请参考strongSwan官方文档。
1. 放通防火墙策略
放通strongSwan设备的ESP协议(IP协议号50)、UDP500端口、UDP4500端口。
iptables -I INPUT -p 50 -j ACCEPT
iptables -I INPUT -p udp --dport 500 -j ACCEPT
iptables -I INPUT -p udp --dport 4500 -j ACCEPT
2. 开启流量转发功能
echo 1 > /proc/sys/net/ipv4/ip_forward
上述命令为临时性命令,strongSwan设备重启后需重新配置该命令。您可以参见以下内容永久开启strongSwan设备的流量转发功能。
3. 安装strongSwan软件
dnf install epel-release -y
dnf install strongswan-5.9.10 -y
4. 配置双隧道
单出口
单出口基于strongSwan感兴趣流进行配置,直接可以实现双隧道主备切换功能。
备份原始strongSwan配置文件
mv /etc/strongswan/swanctl/swanctl.conf /etc/strongswan/swanctl/swanctl.conf.bak
新建strongSwan配置文件
vi /etc/strongswan/swanctl/swanctl.conf
根据场景示例中的规划,添加并保存如下配置
connections { vco1 { # 添加IPsec-VPN隧道1的VPN配置 version = 2 # 指定IKE版本,需与阿里云隧道1的IKE版本保持一致,2表示IKEv2。 local_addrs = 10.0.0.1 # 本地网卡的ip地址 remote_addrs = 3.3.XX.XX # 指定隧道1对端的IP地址为阿里云隧道1的网关IP地址,即IPsec地址1。 dpd_delay = 10 rekey_time = 84600 # 指定隧道1的SA生存周期,需与阿里云隧道1 IKE配置中的SA生存周期保持一致。 over_time = 1800 proposals = aes-sha1-modp1024 # 指定隧道1的加密算法、认证算法、DH分组,需与阿里云隧道1 IKE配置中的加密算法、认证算法、DH分组保持一致,group2对应的是modp1024。 encap = yes local { auth = psk # 本段认证方式选择PSK模式,即预共享密钥方式。 id = 1.1.XX.XX # 本地公网出口IP,需与阿里云隧道1的RemoteId保持一致。 } remote { auth = psk # 对端认证方式选择PSK方式,即阿里云使用预共享密钥方式。 id = 3.3.XX.XX # 阿里云侧IPsec地址1,需与阿里云隧道1的LocalId保持一致。 } children { vco_child1 { local_ts = 10.0.0.0/16 # 本地侧感兴趣流,填写本地私网网段10.0.0.0/16。 remote_ts = 172.16.0.0/16 # 阿里云侧感兴趣流,填写VPC网段172.16.0.0/16。 mode = tunnel rekey_time = 85500 life_time = 86400 # 指定隧道1的SA生存周期,需与阿里云隧道1 IPsec配置中的SA生存周期保持一致。 dpd_action = restart start_action = start close_action = start esp_proposals = aes-sha1-modp1024 # 指定隧道1的加密算法、认证算法、DH分组,需与阿里云隧道1 IPsec配置中的加密算法、认证算法、DH分组保持一致,group2对应的是modp1024。 } } } vco2 { # 添加IPsec-VPN隧道2的VPN配置 version = 2 # 指定IKE版本,需与阿里云隧道2的IKE版本保持一致,2表示IKEv2。 local_addrs = 10.0.0.1 # 本地网卡的ip地址 remote_addrs = 4.4.XX.XX # 指定隧道 址,即IPsec地址2。 dpd_delay = 10 rekey_time = 84600 # 指定隧道2的SA生存周期,需与阿里云隧道2 IKE配置中的SA生存周期保持一致。 over_time = 1800 proposals = aes-sha1-modp1024 # 指定隧道2的加密算法、认证算法、DH分组,需与阿里云隧道2 IKE配置中的加密算法、认证算法、DH分组保持一致,group2对应的是modp1024。 encap = yes local { auth = psk # 本端认证方式选择PSK方式,即预共享密钥方式。 id = 1.1.XX.XX # 本地公网出口IP,与阿里云隧道2的RemoteId保持一致。 } remote { auth = psk # 对端认证方式选择PSK方式,即阿里云使用预共享密钥方式。 id = 4.4.XX.XX # 阿里云侧IPsec地址2,需与阿里云隧道2的LocalId保持一致。 } children { vco_child2 { local_ts = 10.0.0.0/16 # 本地侧感兴趣流,填写本地私网网段10.0.0.0/16。 remote_ts = 172.16.0.0/16 # 阿里云侧感兴趣流,填写VPC网段172.16.0.0/16。 mode = tunnel rekey_time = 85500 life_time = 86400 # 指定隧道2的SA生存周期,需与阿里云隧道1 IPsec配置中的SA生存周期保持一致。 dpd_action = restart start_action = start close_action = start esp_proposals = aes-sha1-modp1024 # 指定隧道2的加密算法、认证算法、DH分组,需与阿里云隧道2 IPsec配置中的加密算法、认证算法、DH分组保持一致,group2对应的是modp1024。 } } } } secrets { ike-vco1 { secret = ChangeMe*** # 指定隧道1的预共享密钥,需与阿里云隧道1的预共享密钥保持一致。 } ike-vco2 { secret = ChangeMe*** # 指定隧道2的预共享密钥,需与阿里云隧道2的预共享密钥保持一致。 } }
重启strongSwan进程
systemctl restart strongswan
查看隧道状态
watch swanctl --list-sas
如图,strongSwan设备和VPN网关之间已经正常建立了IPsec-VPN连接。
双出口
双出口基于XFRM虚拟网络接口实现,使用XFRM虚拟网络接口需要安装strongSwan 5.8.0或以上版本,同时要求Linux内核版本为4.19及以上、iproute2版本为5.1.0及以上,且内核支持xfrm模块(lsmod | grep xfrm
无显示则不支持)。更多信息,请参见XFRM Interfaces on Linux。
添加去往阿里云侧2个IPsec地址的路由,使IPsec地址1通过eth0出口访问,IPsec地址2通过eth1出口访问
ip route add 3.3.XX.XX via 10.0.0.253 dev eth0 #10.0.0.253是私网网关地址 ip route add 4.4.XX.XX via 10.0.0.253 dev eth1
确保下面2个IPsec地址能ping通
ping 3.3.XX.XX ping 4.4.XX.XX
创建2个虚拟网络接口,用于建立IPsec-VPN隧道
ip link add ipsec0 type xfrm dev eth0 if_id 42 # 创建隧道1 XFRM虚拟网络接口,接口ID为42,底层接口为公网接口eth0。 ip link add ipsec1 type xfrm dev eth1 if_id 43 # 创建隧道2 XFRM虚拟网络接口,接口ID为43,底层接口为公网接口eth1。 ip link set ipsec0 up # 启动隧道1 XFRM虚拟网络接口。 ip link set ipsec1 up # 启动隧道2 XFRM虚拟网络接口。
重要创建虚拟网络接口的配置为临时性配置,strongSwan设备重启后,需要重新添加该配置,并执行
sudo systemctl restart strongswan;swanctl --load-all
命令(该命令需要root权限)。您可以参见以下内容为strongSwan设备添加开机自动启动脚本,strongSwan设备重启后会自动重新添加虚拟网络接口。
创建2个脚本,供strongSwan调用并配置路由,从而控制流量传输
新建并编辑/root/connect_1.sh脚本
vi /root/connect_1.sh
添加并保存如下内容:
#!/usr/bin/env bash if [ x"$PLUTO_VERB" == "xup-client" ]; then echo "ip route add 172.16.0.0/16 dev ipsec0" >> /root/vpn_route.log;ip route add 172.16.0.0/16 dev ipsec0 metric 100 elif [ x"$PLUTO_VERB" == "xdown-client" ]; then echo "ip route del 172.16.0.0/16 dev ipsec0" >> /root/vpn_route.log;ip route del 172.16.0.0/16 dev ipsec0 metric 100 fi
脚本功能:如果隧道1的状态是UP,则添加路由使本地数据中心去往阿里云VPC(172.16.0.0/16)的流量通过隧道1 XFRM虚拟网络接口传输,同时指定该路由的metric值为100,使该路由的优先级高于指向隧道2 XFRM虚拟网络接口的路由。如果隧道1的状态是DOWN,则撤销该路由。
新建并编辑/root/connect_2.sh脚本
vi /root/connect_2.sh
添加并保存如下内容:
#!/usr/bin/env bash if [ x"$PLUTO_VERB" == "xup-client" ]; then echo "ip route add 172.16.0.0/16 dev ipsec1" >> /root/vpn_route.log;ip route add 172.16.0.0/16 dev ipsec1 metric 101 elif [ x"$PLUTO_VERB" == "xdown-client" ]; then echo "ip route del 172.16.0.0/16 dev ipsec1" >> /root/vpn_route.log;ip route del 172.16.0.0/16 dev ipsec1 metric 101 fi
脚本功能:如果隧道2的状态是UP,则添加路由使本地数据中心去往阿里云VPC(172.16.0.0/16)的流量通过隧道2 XFRM虚拟网络接口传输,同时指定该路由的metric值为101,使该路由的优先级低于指向隧道1 XFRM虚拟网络接口的路由。如果隧道2的状态是DOWN,则撤销该路由。
为2个脚本赋予可执行权限
sudo chmod +x /root/connect_1.sh sudo chmod +x /root/connect_2.sh
修改strongSwan配置文件
备份原始strongSwan配置文件。
mv /etc/strongswan/swanctl/swanctl.conf /etc/strongswan/swanctl/swanctl.conf.bak
新建strongSwan配置文件。
vi /etc/strongswan/swanctl/swanctl.conf
根据场景示例中IPsec参数规划,添加并保存如下配置
connections { vco1 { # 添加IPsec-VPN隧道1的VPN配置 version = 2 # 指定IKE版本,需与阿里云隧道1的IKE版本保持一致,2表示IKEv2。 local_addrs = 10.0.0.1 # 第1个本地网卡的ip地址 remote_addrs = 3.3.XX.XX # 指定隧道1对端的IP地址为阿里云隧道1的网关IP地址,即IPsec地址1。 dpd_delay = 10 rekey_time = 84600 # 指定隧道1的SA生存周期,需与阿里云隧道1 IKE配置中的SA生存周期保持一致。 over_time = 1800 proposals = aes-sha1-modp1024 # 指定隧道1的加密算法、认证算法、DH分组,需与阿里云隧道1 IKE配置中的加密算法、认证算法、DH分组保持一致,group2对应的是modp1024。 encap = yes local { auth = psk # 本段认证方式选择PSK模式,即预共享密钥方式。 id = 1.1.XX.XX # 第1个本地公网出口IP,需与阿里云隧道1的RemoteId保持一致。 } remote { auth = psk # 对端认证方式选择PSK方式,即阿里云使用预共享密钥方式。 id = 3.3.XX.XX # 阿里云侧IPsec地址1,需与阿里云隧道1的LocalId保持一致。 } children { vco_child1 { local_ts = 0.0.0.0/0 # 阿里云目的路由模式对应的感兴趣流是0.0.0.0/0。 remote_ts = 0.0.0.0/0 # 阿里云目的路由模式对应的感兴趣流是0.0.0.0/0。 mode = tunnel rekey_time = 85500 life_time = 86400 # 指定隧道1的SA生存周期,需与阿里云隧道1 IPsec配置中的SA生存周期保持一致。 dpd_action = restart start_action = start close_action = start esp_proposals = aes-sha1-modp1024 # 指定隧道1的加密算法、认证算法、DH分组,需与阿里云隧道1 IPsec配置中的加密算法、认证算法、DH分组保持一致,group2对应的是modp1024。 if_id_out = 42 # 指定隧道1的出接口和入接口为隧道1 XFRM虚拟网络接口。 if_id_in = 42 updown = /root/connect_1.sh # 根据隧道1的UP和DOWN状态执行/root/connect_1.sh脚本,以配置路由。 } } } vco2 { # 添加IPsec-VPN隧道2的VPN配置 version = 2 # 指定IKE版本,需与阿里云隧道2的IKE版本保持一致,2表示IKEv2。 local_addrs = 10.0.0.2 # 第2个本地网卡的ip地址。 remote_addrs = 4.4.XX.XX # 指定隧道2对端的IP地址为阿里云隧道2的网关IP地址,即IPsec地址2。 dpd_delay = 10 rekey_time = 84600 # 指定隧道2的SA生存周期,需与阿里云隧道2 IKE配置中的SA生存周期保持一致。 over_time = 1800 # proposals = aes-sha1-modp1024 # 指定隧道2的加密算法、认证算法、DH分组,需与阿里云隧道2 IKE配置中的加密算法、认证算法、DH分组保持一致,group2对应的是modp1024。 encap = yes local { auth = psk # 本端认证方式选择PSK方式,即预共享密钥方式。 id = 2.2.XX.XX # 第2个本地公网出口IP,,需与阿里云隧道2的RemoteId保持一致。 } remote { auth = psk # 对端认证方式选择PSK方式,即阿里云使用预共享密钥方式。 id = 4.4.XX.XX # 阿里云侧IPsec地址2,需与阿里云隧道2的LocalId保持一致。 } children { vco_child2 { local_ts = 0.0.0.0/0 # 阿里云目的路由模式对应的感兴趣流是0.0.0.0/0 remote_ts = 0.0.0.0/0 # 阿里云目的路由模式对应的感兴趣流是0.0.0.0/0 mode = tunnel rekey_time = 85500 life_time = 86400 # 指定隧道2的SA生存周期,需与阿里云隧道1 IPsec配置中的SA生存周期保持一致。 dpd_action = restart start_action = start close_action = start esp_proposals = aes-sha1-modp1024 # 指定隧道2的加密算法、认证算法、DH分组,需与阿里云隧道2 IPsec配置中的加密算法、认证算法、DH分组保持一致,group2对应的是modp1024。 if_id_out = 43 # 指定隧道2的出接口和入接口为隧道2 XFRM虚拟网络接口。 if_id_in = 43 updown = /root/connect_2.sh # 根据隧道2的UP和DOWN状态执行/root/connect_2.sh脚本,以配置路由。 } } } } secrets { ike-vco1 { secret = ChangeMe*** # 指定隧道1的预共享密钥,需与阿里云隧道1的预共享密钥保持一致。 } ike-vco2 { secret = ChangeMe*** # 指定隧道2的预共享密钥,需与阿里云隧道2的预共享密钥保持一致。 } }
重启strongSwan进程
vi /etc/strongswan/swanctl/swanctl.conf
查看路由
route -n
查看隧道状态
watch swanctl --list-sas
如图,strongSwan设备和VPN网关之间已经正常建立了IPsec-VPN连接。
5. 验证连通性和高可用性
验证strongSwan设备和VPC之间的连通性。
在strongSwan设备
ping
阿里云VPC内的任意1台ECS,如果能Ping通,则证明连通正常。ping <VPC内1台ECS的地址>
验证IPsec-VPN连接的高可用性。
保持Ping通的情况下,中断IPsec-VPN连接下的主隧道。
您可以通过修改IPsec连接主隧道的预共享密钥来中断主隧道,主隧道两端的预共享密钥不一致,则主隧道会中断。
中断主隧道后,您可以通过
ping
命令观察两侧的连通情况。您会发现ping
流量在短暂中断后,又重新恢复通信。这表示在主隧道中断后,流量自动通过备隧道进行通信。
常见问题
BGP动态路由,使用strongSwan建立IPsec-VPN连接时是否支持?
不支持。
IKEv1版本,使用strongSwan建立IPsec-VPN连接时是否支持?
支持。
配置/etc/strongswan/swanctl/swanctl.conf文件时,指定version = 1
即可。
如何指定感兴趣流?
配置/etc/strongswan/swanctl/swanctl.conf文件时,在以下配置中指定具体网段即可。请确保阿里云侧IPsec连接也配置了感兴趣流模式。
如果本地数据中心侧或阿里云侧需要指定多个网段,strongSwan设备和阿里云IPsec连接均需要使用IKEv2版本。
children {
vco_child1 {
local_ts = 192.168.20.0/24,192.168.50.0/24 # 本地数据中心网段。
remote_ts = 10.0.0.0/16 # 阿里云VPC侧网段。
}
}
strongSwan设备网卡绑定了公网IP地址,如何配置?
对于非NAT的场景,也就是strongSwan设备内部可见的地址为公网IP地址,仅需将/etc/strongswan/swanctl/swanctl.conf配置文件中每条隧道的local_addrs字段改为公网IP地址即可,其他配置不变。
connections {
vco1 {
local_addrs = 1.1.XX.XX # 指定为strongSwan设备网卡绑定的公网IP地址
}
}
单隧道如何配置?
如果您购买的VPN网关实例仅支持建立单隧道模式的IPsec-VPN连接,推荐您升级IPsec-VPN连接为双隧道模式,双隧道模式的IPsec-VPN连接支持可用区级别的容灾,有效提高了网络的高可用性。