Regra Iptables-set para que um contêiner docker possa acessar um serviço em um IP de host

Tenho problemas para acessar uma interface privada do host (ip) de um contêiner docker. Estou bastante certo de que está relacionado às minhas regras Iptables (ou talvez roteamento). Quando eu adiciono o --net=host bandeira para docker run, tudo funciona como esperado. Da mesma forma, quando eu especifico que a Política de entrada 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 para meus serviços (DNS), excluí isso do problema, pois pesquisar isso em combinação com o docker produz em uma área de problema diferente (popular), adicionando ruído aos resultados da pesquisa.

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

Eu tenho as seguintes regras Iptables. Uma combinação de CoreOS, Oceano Digital e Docker eu suponho.

-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 forever4: 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 executo 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. De modo que o seguinte deve render uma resposta:

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

Quando 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

A minha resolução.conf

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

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

Para ilustrar ainda mais (minhas habilidades de design de arte ASCII superam meu iptables fu, então isso deve 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 de exemplo, mas conheço muito pouco das regras de Iptables mais "avançadas" para entender o que está acontecendo e, portanto, obter o resultado desejado.

Saída de iptables -t nat -nL:

Chain PREROUTING (policy ACCEPT)target     prot opt source               destinationDOCKER     all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCALChain INPUT (policy ACCEPT)target     prot opt source               destinationChain OUTPUT (policy ACCEPT)target     prot opt source               destinationDOCKER     all  --  0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCALChain POSTROUTING (policy ACCEPT)target     prot opt source               destinationMASQUERADE  all  --  172.17.0.0/16        0.0.0.0/0Chain DOCKER (2 references)target     prot opt source               destination

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

1

O contêiner se comunica com o host usando docker0 interface.To permitir tráfego do contêiner adicionar:

-A INPUT -i docker0 -j ACCEPT

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

E como percebi que meu contêiner tinha acesso limitado (digamos apenas a porta 22) à interface do host em vez de desligar totalmente da rede host, revisei minhas regras 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. Portanto, adicionei regras semelhantes para permitir que meu contêiner acesse outras portas de host desejadas, o que acho que poderia ser uma maneira um pouco mais precisa de abrir o acesso à rede de host aos contêineres.

Acho que os pacotes do contêiner vêm da interface docker0, não do eth1. tente`- uma entrada-I docker0-J aceitar’

Certamente, obrigado por ajudar até agora: Chain PREROUTING (policy ACCEPT)target prot opt source desti - Pastebin.com (não se encaixou no comentário…) --[editar]–> atualizou o link para um pastebin que não expira.

Talvez eu não tenha entendido corretamente o seu problema, mas não vejo nenhuma regra para permitir consultas DNS no host. Além disso, ip_forward está habilitado?

Olá @ LaurentiuRoescu . ` $ cat / proc / sys / net / ipv4 / ip_forward - > 1 ’ e '- a entrada-I eth1-j ACCEPT ’ aceita todas as conexões na interface private. Quais regras você está perdendo?

Eu acho que você acertou @LaurentiuRoescu. Quando adiciono sua linha, parece funcionar. Nunca imaginei que fosse algo tão trivial… Você poderia adicioná-lo como uma resposta à minha pergunta? Gostaria de recompensar a sua resposta.