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=host
bandera 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
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?$ cat /proc/sys/net/ipv4/ip_forward -> 1
y-A INPUT -i eth1 -j ACCEPT
acepta todas las conexiones en la interfaz privada . ¿Qué reglas te estás perdiendo?-A INPUT -i docker0 -j ACCEPT
Respuestas:
El contenedor se comunica con el host mediante la
docker0
interfaz. Para permitir el tráfico del contenedor, agregue:fuente
iptables -A INPUT -j LOG
. El selloIN=docker0
habrí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!Me he encontrado con una situación muy similar, pero la adición
-A INPUT -i docker0 -j ACCEPT
abrirá 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.fuente
-i docker0
debe 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.