J'ai des problèmes pour accéder à une interface privée hôte (IP) à partir d'un conteneur Docker. Je suis assez certain que c'est lié à mes règles Iptables (ou peut-être au routage). Lorsque j'ajoute le --net=host
drapeau à docker run
, tout fonctionne comme prévu. De même, lorsque je précise que la politique INPUT suit un libéral -P INPUT ACCEPT
, les choses fonctionnent aussi comme je m'y attendais. Cependant, ce sont des options indésirables et dangereuses que j'aimerais éviter.
Puisqu'il n'est pas spécifique à mes services (DNS), j'ai exclu cela du problème, car la recherche de cela en combinaison avec docker donne un autre problème (populaire), ajoutant du bruit aux résultats de la recherche.
La liaison de conteneurs Docker n'est pas non plus une option viable, car certains conteneurs doivent être exécutés avec l'option --net = host, empêchant la liaison et je souhaite créer une situation cohérente dans la mesure du possible.
J'ai les règles Iptables suivantes. Une combinaison de CoreOS, Digital Ocean et Docker, je suppose.
-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
Mes interfaces hôtes (pertinentes):
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
Et je lance un conteneur 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.
À ce stade, je veux pouvoir utiliser un service local, lié le 10.129.112.210:53. Pour que ce qui suit donne une réponse:
$ ping google.com
^C
$ ping user.skydns.local
^C
Lorsque j'exécute la même commande depuis mon hôte:
$ 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
Mon 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
Le point ici n'est pas d'accéder aux hôtes publics, mais plutôt aux hôtes internes, en utilisant le service DNS local disponible sur l'hôte (via une autre instance de docker).
Pour l'illustrer encore plus (mes compétences en conception d'art ascii dépassent mes fu iptables, ce qui devrait en dire assez à ce stade):
______________________________________________
| __________________________ 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)
J'ai cherché, lu et appliqué différents exemples de configurations Iptables, mais je connais trop peu de règles Iptables plus "avancées" pour comprendre ce qui se passe et ainsi obtenir le résultat souhaité.
Sortie 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
Sortie de cat /proc/sys/net/ipv4/ip_forward
:
1
iptables -t nat -nL
? Avez-vous fait une analyse de paquet, disons faire un ping depuis le conteneur source et utiliser tcpdump pour capturer les paquets sur l'hôte.$ cat /proc/sys/net/ipv4/ip_forward -> 1
et-A INPUT -i eth1 -j ACCEPT
accepte toutes les connexions sur l' interface privée . Quelles règles vous manquent?-A INPUT -i docker0 -j ACCEPT
Réponses:
Le conteneur communique avec l'hôte à l'aide de l'
docker0
interface. Pour autoriser le trafic provenant du conteneur, ajoutez:la source
iptables -A INPUT -j LOG
. Le timbreIN=docker0
aurait été très utile pour déterminer quelle modification de règle était nécessaire. À ne pas retirer du travail de Laurentiu, qui était excellent - +1 de ma part!J'ai rencontré une situation très similaire, mais l'ajout
-A INPUT -i docker0 -j ACCEPT
ouvrira tous les accès sur mon interface eth0 de l'hôte docker aux conteneurs, ce qui n'est absolument pas ce que je voulais.Et comme j'ai remarqué que mon conteneur avait juste un accès limité (disons seulement le port 22) à l'interface hôte au lieu d'être totalement fermé du réseau hôte, j'ai passé en revue mes règles iptables et trouvé une règle dans la chaîne IN_public_allow qui devrait être responsable de cela. La règle est
-A IN_public_allow -p tcp -m tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT
. J'ai donc ajouté des règles similaires pour permettre à mon conteneur d'accéder aux autres ports hôtes souhaités, ce qui, je pense, pourrait être un moyen un peu plus précis d'ouvrir l'accès au réseau hôte aux conteneurs.la source
-i docker0
devrait garantir que cela n'affectera pas le trafic qui n'arrive pas via le réseau docker0. Votre grammaire n'est cependant pas claire. Peut-être que vous disiez que l'accès sortant des hôtes Docker via eth0 était activé, ce qui pourrait être vrai. Je suis d'accord que des règles plus ciblées ne sont possibles que si vous en avez besoin.