允许Docker容器在主机上使用IPSEC VPN

我的工作站上有Docker和IPSEC VPN通道,但容器无法访问VPN后面的主机。 有什么我可以做的,例如IPTables或路线允许访问? [注:目前我正在libvirt托pipe的虚拟机中运行这些testing,然后libvirt桥的地址为192.168.122.1]

我的networking设置如下所示:

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: ens3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 52:54:00:0f:f2:bb brd ff:ff:ff:ff:ff:ff inet 192.168.122.87/24 brd 192.168.122.255 scope global dynamic ens3 valid_lft 3490sec preferred_lft 3490sec inet6 fe80::5054:ff:fe0f:f2bb/64 scope link valid_lft forever preferred_lft forever 3: tap0: <BROADCAST,UP,LOWER_UP> mtu 1380 qdisc pfifo_fast state UNKNOWN qlen 500 link/ether d6:2b:f6:24:c5:1c brd ff:ff:ff:ff:ff:ff inet 172.20.1.29/24 brd 172.20.1.255 scope global tap0 valid_lft forever preferred_lft forever inet6 fe80::d42b:f6ff:fe24:c51c/64 scope link valid_lft forever preferred_lft forever 4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP link/ether 02:42:24:7f:6a:1a brd ff:ff:ff:ff:ff:ff inet 172.17.0.1/16 scope global docker0 valid_lft forever preferred_lft forever inet6 fe80::42:24ff:fe7f:6a1a/64 scope link valid_lft forever preferred_lft forever 

我的路由看起来像这样(VPN端点IP混淆):

 default via 192.168.122.1 dev ens3 proto static metric 100 10.0.0.0/8 via 172.20.1.29 dev tap0 proto static 10.11.12.13 via 192.168.122.1 dev ens3 proto static 172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 172.20.1.0/24 dev tap0 proto kernel scope link src 172.20.1.29 192.168.122.0/24 dev ens3 proto kernel scope link src 192.168.122.87 metric 100 

我可以看到一些现有的masq规则,当我从容器中发送testingping命令时,第一个规则中的包计数器递增:

 [robin@rhel72 ~]$ sudo iptables -t nat -L -n -v --line-numbers | sed -n '/^Chain POSTROUTING /,/^$/ p' Chain POSTROUTING (policy ACCEPT 4 packets, 534 bytes) num pkts bytes target prot opt in out source destination 1 63 4290 MASQUERADE all -- * !docker0 172.17.0.0/16 0.0.0.0/0 2 473 30282 POSTROUTING_direct all -- * * 0.0.0.0/0 0.0.0.0/0 3 473 30282 POSTROUTING_ZONES_SOURCE all -- * * 0.0.0.0/0 0.0.0.0/0 4 473 30282 POSTROUTING_ZONES all -- * * 0.0.0.0/0 0.0.0.0/0 

最后,我可以看到当我从容器中运行ping -c1 tcpdump连接时,看起来像是部分响应:

 [robin@rhel72 ~]$ sudo tcpdump -i any -n 'icmp' tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on any, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes 09:55:01.919214 IP 172.17.0.2 > 10.60.1.201: ICMP echo request, id 27, seq 1, length 64 09:55:01.919214 IP 172.17.0.2 > 10.60.1.201: ICMP echo request, id 27, seq 1, length 64 09:55:01.940613 IP 10.60.1.201 > 172.20.1.29: ICMP echo reply, id 27, seq 1, length 64 

编辑1

Docker容器内的路由表是:

 [root@451c1c9c708c /]# ip route default via 172.17.0.1 dev eth0 172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.2 

值得一提的是,我使用--icc=false标志来运行Docker守护进程来隔离容器。

我写了一个python程序来封装ipsec,它安装了iptables条目,以允许docker容器和VPN通道通信:

https://github.com/cbrichford/docker-ipsec

而不是: ipsec up

你这样做: docker-ipsec up

此脚本可能需要一些工作才能使用最新的dockernetworkingfunction,但是使用旧的默认docker0网桥。

如果你不想用我的脚本来编辑iptables,那么在这里你是如何构buildiptables命令的:

  1. 找出VPN中主机的虚拟IP地址。 调用这个虚拟IP。
  2. 找出VPN中IP地址的CIDR块。 如果VPN中的IP地址始终为10.10.XX格式,那么您的CIDR块将为10.10.0.0/16。 调用这个vpnSubnet
  3. 找出默认的路由接口。 这将会像“eth0”一样。 这是我用来查找它的命令: sudo ip route show | grep -e "^default" | awk -- "{ print \$5 }" sudo ip route show | grep -e "^default" | awk -- "{ print \$5 }" sudo ip route show | grep -e "^default" | awk -- "{ print \$5 }" 。 调用这个默认的路由接口
  4. 找出您希望授予访问您的VPN的泊坞网的CIDR块。 我用这个命令find它: sudo ip route show | grep -e "[[:space:]]dev[[:space:]]docker" | awk -- "{ print \$1 }" sudo ip route show | grep -e "[[:space:]]dev[[:space:]]docker" | awk -- "{ print \$1 }" sudo ip route show | grep -e "[[:space:]]dev[[:space:]]docker" | awk -- "{ print \$1 }" 。 调用这个dockerSubnet。

你需要运行的iptables命令是: sudo \ iptables \ -j SNAT \ -t nat \ -I POSTROUTING 1 \ -o ${defaultRouteInterface} \ -d "${vpnSubnet}" \ -s "${dockerSubnet}" \ --to-source "${virtualIP}"

基于@ ChristopherBrichford的回答,我设法将这个公式归结为下面的命令。 这是基于我对有关各种运动部件的有限理解。

 sudo iptables -j SNAT -t nat -I POSTROUTING 1 \ -o $(ip route show | grep -e "^default" | awk -- "{ print \$5 }") \ -d $(ip route list table 220 | grep -o '^[0-9.]*/[0-9]*') \ -s $(ip route show | grep -e ":space:dev:space:docker" | awk -- "{ print \$1 }") \ --to-source $(ifconfig | grep -o 'PtP:[^ ]*' | cut -d: -f2) 

一个更可用和更新的版本可作为一个要点 。