У меня есть Docker и VPN-туннель IPSEC на моей рабочей станции, но контейнеры не могут получить доступ к узлам, находящимся за VPN. Могу ли я что-нибудь сделать, например с IPTables или маршрутами для разрешения доступа? [Примечание: в настоящее время я запускаю эти тесты из виртуальной машины, размещенной в libvirt, тогда мост libvirt имеет адрес 192.168.122.1]
Мои настройки сети выглядят так:
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
Мои маршруты выглядят так (IP конечной точки VPN запутан):
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
Я вижу некоторые существующие правила масок, счетчик пакетов на первом правиле увеличивается, когда я отправляю тестовые пинги из контейнера:
[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
Наконец, я могу увидеть то, что выглядит как частичный ответ, когда я tcpdump соединение во время работы ping -c1
изнутри контейнера:
[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
Возможно, стоит отметить, что я запускаю демон Docker с помощью --icc=false
флаг для изоляции контейнеров.
Я написал программу на Python для обертывания ipsec, которая устанавливает записи iptables, чтобы контейнеры докеров могли взаимодействовать с туннелем VPN:
https://github.com/cbrichford/docker-ipsec
Вместо того, чтобы делать: ipsec up
Вы делаете: docker-ipsec up
Этот сценарий может потребовать некоторой работы для использования с последними сетевыми функциями докеров, но работал со старым по умолчанию docker0
мост.
Если вы не хотите использовать мой скрипт для редактирования iptables, вот как вы создаете команду iptables:
sudo ip route show | grep -e "^default" | awk -- "{ print \$5 }"
. Назовите это defaultRouteInterfacesudo 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 'P-t-P:[^ ]*' | cut -d: -f2)
Более удобная и обновленная версия доступно как суть.