Regla de Iptables: establecida para que un contenedor de docker pueda acceder a un servicio en una IP de host

Tengo problemas para acceder a una interfaz privada (ip) de host desde un contenedor docker. Estoy bastante seguro de que está relacionado con mis reglas de Iptables (o quizás con el enrutamiento). Cuando agrego el --net=host bandera a docker run, todo funciona como se esperaba. De manera similar, cuando especifico que la política de ENTRADA sigue un liberal -P INPUT ACCEPT, las cosas también funcionan como yo esperaría. Sin embargo, estas son opciones indeseables e inseguras que me gustaría evitar.

Como no es específico de mis servicios (DNS), lo he excluido del problema, ya que buscarlo en combinación con docker produce un área problemática diferente (popular), lo que agrega ruido a los resultados de búsqueda.

Además, la vinculación de contenedores Docker no es una opción viable, porque ciertos contenedores deben ejecutarse con la opción --net=host, lo que impide la vinculación y quiero crear una situación coherente siempre que sea posible.

Tengo las siguientes reglas de Iptables. Una combinación de CoreOS, Digital Ocean y Docker, supongo.

-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

Mis 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

Y ejecuto un contenedor 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.

En este punto, quiero poder usar un servicio local, vinculado a 10.129.112.210: 53. De modo que lo siguiente debería dar una respuesta:

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

Cuando ejecuto el mismo comando desde mi 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

Mi resolv.conf

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

El punto aquí no es acceder a los hosts públicos, sino a los internos, utilizando el servicio DNS local disponible en el host (a través de otra instancia de docker).

Para ilustrarlo aún más (mis habilidades de diseño de arte ascii superan mis habilidades de iptables, por lo que debería ser suficiente en este punto):

 ______________________________________________|  __________________________           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)

He buscado, leído y aplicado diferentes configuraciones de Iptables de ejemplo, pero sé muy poco de las reglas de Iptables más "avanzadas" para comprender qué está sucediendo y, por lo tanto, obtener el resultado deseado.

Salida 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

Salida de cat /proc/sys/net/ipv4/ip_forward:

1

El contenedor se comunica con el host mediante docker0 interface.To permitir tráfico desde el contenedor agregar:

-A INPUT -i docker0 -j ACCEPT

Me he encontrado con una situación muy similar, pero agregando -A INPUT -i docker0 -j ACCEPT abrirá todos los accesos a través de mi interfaz eth0 de docker host a contenedores, lo que no es en absoluto lo que pretendía.

Y como noté que mi contenedor solo tenía acceso limitado(digamos solo el puerto 22) a la interfaz del host en lugar de estar totalmente cerrado desde la red del host, revisé mis reglas de iptables y encontré una regla en la cadena IN_public_allow que debería ser responsable de esto. La regla es -A IN_public_allow -p tcp -m tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT. Así que agregué reglas similares para permitir que mi contenedor acceda a otros puertos de host deseados, lo que creo que podría ser una forma un poco más precisa de abrir el acceso a la red de host a los contenedores.

Creo que los paquetes del contenedor provienen de la interfaz docker0, no de eth1. prueba - A INPUT-i docker0-j ACCEPT

Ciertamente, gracias por ayudar hasta ahora: Chain PREROUTING (policy ACCEPT)target prot opt source desti - Pastebin.com (No encajaba en el comentario…) --[editar]–> Actualizado el enlace a un pastebin que no caduque.

Tal vez no entendí correctamente su problema, pero no veo ninguna regla para permitir consultas DNS en el host. Además, ¿está habilitado ip_forward?

Hola @LaurentiuRoescu. cat cat / proc / sys / net / ipv4 / ip_forward -> 1 y -A INPUT-i eth1-j ACCEPT acepta todas las conexiones en la interfaz private. ¿Qué reglas te estás perdiendo?

Creo que lo lograste @LaurentiuRoescu. Cuando agrego tu línea, parece funcionar. Nunca pensé que fuera algo tan trivial… ¿Podría agregarlo como respuesta a mi pregunta? Me gustaría recompensar tu respuesta.

Puede publicar el resultado de ‘iptables-t nat-nL’? Si realizó algún análisis de paquetes, por ejemplo, haga un ping desde el contenedor de origen y use tcpdump para capturar los paquetes en el host.