Назад | Перейти на главную страницу

Разрешить контейнерам Docker использовать IPSEC VPN на хосте

У меня есть 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:

  1. Выясните виртуальный IP-адрес хоста в VPN. Назовите этот virtualIP.
  2. Выясните блок CIDR для IP-адреса в VPN. Если IP-адрес в VPN всегда имеет форму 10.10.X.X, тогда ваш блок CIDR будет 10.10.0.0/16. Назовите это vpnSubnet
  3. Выясните интерфейс маршрута по умолчанию. Это будет что-то вроде "eth0". Вот команда, которую я использую, чтобы найти его: sudo ip route show | grep -e "^default" | awk -- "{ print \$5 }". Назовите это defaultRouteInterface
  4. Выясните блок CIDR для сети докеров, которой вы хотите предоставить доступ к своей VPN. Я использую эту команду, чтобы найти его: 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 'P-t-P:[^ ]*' | cut -d: -f2)

Более удобная и обновленная версия доступно как суть.