Conjunto de regras Iptables para que um contêiner do Docker possa acessar um serviço em um IP do host

18

Eu tenho problemas para acessar uma interface privada de host (ip) de um contêiner docker. Tenho quase certeza de que está relacionado às minhas regras do Iptables (ou talvez ao roteamento). Quando eu adiciono o sinalizador --net=host a docker run , tudo funciona conforme o esperado. Da mesma forma, quando eu especificar que a política INPUT está seguindo um liberal -P INPUT ACCEPT , as coisas também funcionam como eu esperaria. No entanto, essas são opções indesejáveis e inseguras que eu gostaria de evitar.

Como não é específico dos meus serviços (DNS), excluí isso do problema, pois a pesquisa em combinação com o docker gera uma área problemática (popular) diferente, adicionando ruído aos resultados da pesquisa.

Também a vinculação de contêineres do Docker não é uma opção viável, porque determinados contêineres precisam ser executados com a opção --net = host, impedindo a vinculação e quero criar uma situação consistente onde for possível.

Eu tenho as seguintes regras do Iptables. Uma combinação de CoreOS, Digital Ocean e Docker I assume.

-P INPUT DROP
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-N DOCKER
-A INPUT -i lo -j ACCEPT
-A INPUT -i eth1 -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 0 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 3 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 11 -j ACCEPT
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT

Minhas interfaces de host (relevantes):

3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    inet 10.129.112.210/16 brd 10.129.255.255 scope global eth1
       valid_lft forever preferred_lft forever
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
    inet 172.17.42.1/16 scope global docker0
       valid_lft forever preferred_lft forever

E eu uso um contêiner docker:

$ docker run --rm -it --dns=10.129.112.210 debian:jessie # Specifying the DNS is so that the public DNS servers aren't used.

Neste ponto, quero poder usar um serviço local, vinculado a 10.129.112.210:53. Para que o seguinte forneça uma resposta:

$ ping google.com
^C
$ ping user.skydns.local
^C

Quando eu executo o mesmo comando do meu host:

$ ping photo.skydns.localPING photo.skydns.local (10.129.112.206) 56(84) bytes of data.
64 bytes from 10.129.112.206: icmp_seq=1 ttl=64 time=0.790 ms
^C

Meu resolv.conf

$ cat /etc/resolv.conf
nameserver 10.129.112.210
nameserver 127.0.0.1
nameserver 8.8.8.8
nameserver 8.8.4.4

O ponto aqui não é acessar os hosts públicos, mas os internos, usando o serviço DNS local disponível no host (por meio de outra instância docker).

Para ilustrar ainda mais (minhas habilidades de design de arte ascii superam meu iptables fu, de modo que deveria dizer o suficiente neste momento):

 ______________________________________________
|  __________________________           Host   |
| |   Docker DNS container   |                 |
|  ''''''''''''''''''''''|'''                  |
|                        |                     |
|     ,----------,---( private n. interface )  |
|     |          |                             |
|     |          |   ( public  n. interface )---
|     |          |                             |
|     |          |   ( loopbck n. interface )  |
|     |          |                             |
|     |          |                             |
|     |        __|_______________________      |
|     |       | Docker service container |     |
|     |        ''''''''''''''''''''''''''      |
|     |                                        |
|     |                                        |
| [ Local host service using DNS. ]            |
|                                              |
|______________________________________________|

  private (host) network interface: eth1 (10.129.0.0/16)
  Docker network interface: docker0 (172.17.0.0/16)

Eu pesquisei, li e apliquei diferentes configurações de Iptables, mas sei muito pouco das regras mais avançadas do Iptables para entender o que está acontecendo e, assim, obter o resultado desejado.

Saída de iptables -t nat -nL :

Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
DOCKER     all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL

Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
DOCKER     all  --  0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCAL

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
MASQUERADE  all  --  172.17.0.0/16        0.0.0.0/0

Chain DOCKER (2 references)
target     prot opt source               destination

Saída de cat /proc/sys/net/ipv4/ip_forward :

1
    
por Dynom 12.07.2015 / 18:13

2 respostas

14

O contêiner se comunica com o host usando a interface docker0 . Para permitir tráfego do contêiner, adicione:

-A INPUT -i docker0 -j ACCEPT
    
por 27.07.2015 / 11:16
0

Encontrei uma situação muito semelhante, mas a adição de -A INPUT -i docker0 -j ACCEPT abrirá todos os acessos pela minha interface eth0 do host do docker para contêineres, o que não é absolutamente o que eu pretendia.

E como percebi que o meu contêiner tinha acesso limitado (digamos apenas a porta 22) à interface do host em vez de totalmente desligado da rede do host, examinei minhas regras do iptables e encontrei uma regra na cadeia IN_public_allow que deveria ser responsável por isso . A regra é -A IN_public_allow -p tcp -m tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT . Então, adicionei regras semelhantes para permitir que meu contêiner acesse outras portas de host desejadas, o que, na minha opinião, poderia ser uma maneira um pouco mais precisa de abrir o acesso à rede do host a contêineres.

    
por 28.12.2017 / 03:08