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
$ 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
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?