Conjunto de reglas de Iptables para que un contenedor acoplable pueda acceder a un servicio en una IP de host


18

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

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

Además, la vinculación de los contenedores Docker no es una opción viable, ya que ciertos contenedores deben ejecutarse con la opción --net = host, evitando la vinculación y quiero crear una situación coherente cuando 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 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

Y ejecuto un contenedor acoplable:

$ 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 utilizar un servicio local, vinculado a 10.129.112.210:53. Para que lo siguiente produzca 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.conf
nameserver 10.129.112.210
nameserver 127.0.0.1
nameserver 8.8.8.8
nameserver 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 mi fu de iptables, por lo que debería decir lo 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 así obtener el resultado deseado.

Salida 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

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

1

¿Puedes publicar la salida de iptables -t nat -nL? ¿Hizo algún análisis de paquetes, digamos que haga un ping desde el contenedor de origen y use tcpdump para capturar los paquetes en el host?
Daniel t.

Ciertamente, gracias por ayudar hasta ahora: pastebin.com/TAaT73nk (No encaja el comentario ..) - editar -> Actualizó el enlace a un pastebin que no caduca.
Dynom

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?
Laurentiu Roescu

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

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

Respuestas:


14

El contenedor se comunica con el host mediante la docker0interfaz. Para permitir el tráfico del contenedor, agregue:

-A INPUT -i docker0 -j ACCEPT

2
Dynom, una lección que quizás quieras sacar de esto es que registrar todas tus denegaciones es útil, por ejemplo iptables -A INPUT -j LOG. El sello IN=docker0habría sido muy útil para determinar qué ajuste de reglas se necesitaba. Para no quitarle el trabajo a Laurentiu, que fue excelente - ¡+1 de mi parte!
MadHatter apoya a Monica el

55
Para las personas que usan UFW, esto es lo que hice para permitir toda la comunicación desde los contenedores Docker al host: ufw permitir en docker0
Ali Ok

0

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

Y como me di cuenta de que mi contenedor solo tenía acceso limitado (digamos solo el puerto 22) a la interfaz del host en lugar de apagarse por completo de 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 host deseados, lo que creo que podría ser una forma un poco más precisa de abrir el acceso de la red host a los contenedores.


-i docker0debe asegurarse de que esto no afecte el tráfico que no llega a través de la red docker0. Sin embargo, tu gramática no está clara. Tal vez estabas diciendo que el acceso saliente desde los hosts docker a través de eth0 estaba habilitado, lo que podría ser cierto. Estoy de acuerdo en que es posible abrir reglas más específicas solo cuando sea necesario.
mc0e
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.