Permitir que contêineres do Docker usem VPN IPSEC no host

2

Eu tenho o Docker e um túnel IPSEC VPN na minha estação de trabalho, mas os contêineres não podem acessar os hosts por trás da VPN. Existe alguma coisa que eu possa fazer, por ex. com IPTables ou rotas para permitir acesso? [Nota: Atualmente, estou executando esses testes de dentro de uma VM hospedada em libvirt, depois a libvirt bridge tem o endereço 192.168.122.1]

Minha configuração de rede é assim:

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

Minhas rotas se parecem com isso (IP de endpoint VPN ofuscado):

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

Eu posso ver algumas regras de masq existentes, o contador de pacotes na primeira regra é incrementado quando envio pings de teste de um contêiner:

[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

Por fim, posso ver o que parece ser uma resposta parcial quando tcpdump a conexão enquanto estou executando ping -c1 de dentro do contêiner:

[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

EDIT 1

A tabela de roteamento dentro do contêiner do 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

Pode ser interessante notar que estou executando o daemon do Docker usando o sinalizador --icc=false para isolar os contêineres.

    
por Robin 18.04.2016 / 11:00

2 respostas

6

Eu escrevi um programa python para envolver o ipsec que instala entradas do iptables para permitir que contêineres do docker falem com o túnel da VPN:

link

Em vez de fazer: ipsec up

Você faz: docker-ipsec up

Esse script pode precisar de algum trabalho para ser usado com os recursos de rede do docker mais recentes, mas funcionou com o antigo padrão docker0 bridge.

Se você não quiser usar o meu script para editar o iptables, veja como você constrói o comando iptables:

  1. Descobrir o endereço IP virtual do host na VPN. Chame esse virtualIP.
  2. Descobrir o bloco CIDR para o endereço IP na VPN. Se o endereço IP na VPN estiver sempre no formato 10.10.X.X, seu bloco CIDR será 10.10.0.0/16. Chame isso de vpnSubnet
  3. Descobrir a interface de rota padrão. Isso será algo como "eth0". Este é o comando que eu uso para encontrá-lo: sudo ip route show | grep -e "^default" | awk -- "{ print \ }" . Chame esse defaultRouteInterface
  4. Descobrir o bloco CIDR da rede docker que você deseja conceder acesso à sua VPN. Eu este comando para encontrá-lo: sudo ip route show | grep -e "[[:space:]]dev[[:space:]]docker" | awk -- "{ print \ }" . Chame esse dockerSubnet.

O comando iptables que você precisa executar é: sudo \ iptables \ -j SNAT \ -t nat \ -I POSTROUTING 1 \ -o ${defaultRouteInterface} \ -d "${vpnSubnet}" \ -s "${dockerSubnet}" \ --to-source "${virtualIP}"

    
por 18.04.2016 / 19:37
0

Com base na resposta de @ ChristopherBrichford, consegui reduzir a fórmula ao comando abaixo. Isto é baseado no meu entendimento limitado de várias partes móveis envolvidas.

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

Uma versão mais utilizável e atualizada é disponível como uma essência .

    
por 22.10.2016 / 04:23