主机部署Strongswan IPSec隧道后Docker容器无法穿透隧道访问远端网络
主机部署Strongswan IPSec隧道后Docker容器无法穿透隧道访问远端网络
问题场景
我(提问者)在Ubuntu 22.04主机上部署了带bypass-lan插件的Strongswan IPSec隧道,通过ipsec statusall确认连接稳定正常。同时创建了一个Docker桥接网络(命名为app),网段和Strongswan的leftsubnet完全一致(10.22.10.0/24),我的Docker Compose栈里的容器都使用这个网络,还特意给其中一个容器配置了固定IP用于测试。
但遇到了核心问题:容器能正常访问互联网,却完全无法通过IPSec隧道访问远端网络,而且我没有权限修改隧道右侧的配置。
初期排查尝试
一开始我找了网上的iptables SNAT规则来尝试解决,规则模板是:
iptables -j SNAT -t nat -I POSTROUTING 1 -o ${OUT_INTERFACE} -d ${VPN_NETWORK} -s ${DOCKER_NETWORK} --to-source ${VPN_HOST_IP}
我把参数对应成自己的环境:
${OUT_INTERFACE}:Docker桥接网络的接口名(比如br-7b5f3aa28bb9)${VPN_NETWORK}:隧道的rightsubnet${DOCKER_NETWORK}:Strongswan的leftsubnet${VPN_HOST_IP}:主机的公网IP
可惜这条规则没有生效,因为我对iptables的具体逻辑不太熟悉,一时找不到问题所在。后来在另一台同配置的服务器上测试,结果还是失败,于是我导出了当前的iptables规则来分析:
过滤表(filter)规则(执行iptables -S输出)
-A FORWARD -o br-7b5f3aa28bb9 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A FORWARD -o br-7b5f3aa28bb9 -j DOCKER -A FORWARD -i br-7b5f3aa28bb9 ! -o br-7b5f3aa28bb9 -j ACCEPT -A FORWARD -i br-7b5f3aa28bb9 -o br-7b5f3aa28bb9 -j ACCEPT -A DOCKER-ISOLATION-STAGE-1 -i br-7b5f3aa28bb9 ! -o br-7b5f3aa28bb9 -j DOCKER-ISOLATION-STAGE-2 -A DOCKER-ISOLATION-STAGE-2 -o br-7b5f3aa28bb9 -j DROP
NAT表规则(执行iptables -S -t nat输出)
-A POSTROUTING -i br-7b5f3aa28bb9 -m policy --dir in --pol ipsec -j ACCEPT -A POSTROUTING -s 10.22.10.0/24 ! -o br-7b5f3aa28bb9 -j MASQUERADE -A DOCKER -i br-7b5f3aa28bb9 -j RETURN
mangle表没有任何规则。
最终解决方法
折腾了很久才发现问题的根源:我的容器使用了多个网络接口,导致访问隧道远端的流量没有走正确的网卡。最后通过添加两条iptables规则彻底解决了问题:
首先先定义几个变量方便复用(根据自己的实际环境替换):
$DOCKER_NETWORK:Docker桥接网络的网段(比如10.22.10.0/24)$REMOTE_NETWORK:IPSec隧道远端的目标网段(比如10.5.18.38/32或对应的网段)$DOCKER_NETWORK_GATEWAY:Docker桥接网络的网关(比如10.22.10.1)
然后执行以下两条规则:
# 允许Docker网段到远端网段的IPSec流量跳过SNAT,保留源IP让隧道识别 iptables -t nat -I POSTROUTING -s $DOCKER_NETWORK -d $REMOTE_NETWORK -m policy --dir out --pol ipsec -j ACCEPT # 对非Docker网段发往远端的流量,SNAT到Docker桥接网关,确保流量走正确的网卡进入隧道 iptables -t nat -I POSTROUTING -d $REMOTE_NETWORK ! -s $DOCKER_NETWORK -j SNAT --to-source $DOCKER_NETWORK_GATEWAY
备注:内容来源于stack exchange,提问作者yonisolo




