54 votes

Comment limiter les connexions extérieures à un conteneur docker avec iptables ?

Mon objectif est de limiter l'accès aux conteneurs Docker à quelques adresses IP publiques. Existe-t-il un processus simple et reproductible pour atteindre mon objectif ? Ne comprenant que les bases d'iptables tout en utilisant les options par défaut de Docker, je trouve cela très difficile.

J'aimerais faire fonctionner un conteneur, le rendre visible sur l'Internet public, mais n'autoriser les connexions qu'à partir de certains hôtes. Je m'attendrais à ce que la politique d'entrée par défaut soit REJECT et qu'elle n'autorise que les connexions provenant de mes hôtes. Mais les règles et les chaînes NAT de Docker s'interposent et mes règles INPUT sont ignorées.

Quelqu'un peut-il me donner un exemple de la manière d'atteindre mon objectif en partant des hypothèses suivantes ?

  • Hôte de l'IP publique 80.80.80.80 sur eth0
  • Hôte IP privé 192.168.1.10 sur eth1
  • docker run -d -p 3306:3306 mysql
  • Bloquer toutes les connexions vers l'hôte/le conteneur 3306 à l'exception des hôtes 4.4.4.4 et 8.8.8.8

Je suis heureux de lier le conteneur à l'adresse IP locale uniquement, mais j'aurais besoin d'instructions sur la manière de configurer correctement les règles de transfert iptables qui survivent aux redémarrages du processus de docker et de l'hôte.

Gracias.

56voto

SystemParadox Points 807

Deux choses à garder à l'esprit lorsque l'on travaille avec les règles de pare-feu de Docker :

  1. Afin d'éviter que vos règles ne soient prises en compte par Docker, utilisez l'option DOCKER-USER chaîne
  2. Docker effectue le mappage des ports dans le fichier PREROUTING chaîne de la nat table. Cela se produit avant que le filter règles, donc --dest y --dport vous verrez l'IP et le port internes du conteneur. Pour accéder à la destination d'origine, vous pouvez utiliser -m conntrack --ctorigdstport .

Par exemple :

iptables -A DOCKER-USER -i eth0 -s 8.8.8.8 -p tcp -m conntrack --ctorigdstport 3306 --ctdir ORIGINAL -j ACCEPT
iptables -A DOCKER-USER -i eth0 -s 4.4.4.4 -p tcp -m conntrack --ctorigdstport 3306 --ctdir ORIGINAL -j ACCEPT
iptables -A DOCKER-USER -i eth0 -p tcp -m conntrack --ctorigdstport 3306 --ctdir ORIGINAL -j DROP

NOTE : Sans --ctdir ORIGINAL Si le conteneur est connecté au port 3306 d'un autre serveur, cela correspondrait également aux paquets de réponse qui reviennent pour une connexion du conteneur au port 3306 d'un autre serveur, ce qui n'est certainement pas ce que vous voulez ! Vous n'avez pas strictement besoin de cela si, comme moi, votre première règle est -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT qui traitera tous les paquets de réponse, mais il serait plus sûr de continuer à utiliser --ctdir ORIGINAL Quoi qu'il en soit.

13voto

ck1 Points 119

Avec Docker v.17.06, il y a une nouvelle chaîne iptables appelée DOCKER-USER. Celle-ci est destinée à vos règles personnalisées : https://docs.docker.com/network/iptables/

Contrairement à la chaîne DOCKER, il n'est pas réinitialisé lors de la construction/démarrage de conteneurs. Vous pouvez donc ajouter ces lignes à votre configuration iptables/script pour provisionner le serveur avant même d'installer docker et de démarrer les conteneurs :

-N DOCKER
-N DOCKER-ISOLATION
-N DOCKER-USER
-A DOCKER-ISOLATION -j RETURN
-A DOCKER-USER -i eth0 -p tcp -m tcp --dport 3306 -j DROP
-A DOCKER-USER -j RETURN

Maintenant le port pour MySQL est bloqué de l'accès externe (eth0) même si docker ouvre le port pour le monde entier. (Ces règles supposent que votre interface externe est eth0).

Eventuellement, vous devrez nettoyer iptables et redémarrer le service docker, si vous l'avez trop endommagé en essayant de verrouiller le port comme je l'ai fait.

7voto

GGGforce Points 649

MISE À JOUR : Bien que valable en 2015, cette solution n'est plus la bonne.

La réponse semble se trouver dans la documentation de Docker à l'adresse suivante https://docs.docker.com/articles/networking/#the-world

Les règles de transfert de Docker autorisent par défaut toutes les IP sources externes. Pour n'autoriser qu'une IP ou un réseau spécifique à accéder aux conteneurs, insérez une règle annulée au sommet de la chaîne de filtrage DOCKER. Par exemple, pour restreindre l'accès externe de sorte que seule l'IP source 8.8.8.8 puisse accéder aux conteneurs, la règle suivante peut être ajoutée : iptables -I DOCKER -i ext_if ! -s 8.8.8.8 -j DROP

Ce que j'ai fini par faire, c'est.. :

iptables -I DOCKER -i eth0 -s 8.8.8.8 -p tcp --dport 3306 -j ACCEPT
iptables -I DOCKER -i eth0 -s 4.4.4.4 -p tcp --dport 3306 -j ACCEPT
iptables -I DOCKER 3 -i eth0 -p tcp --dport 3306 -j DROP

Je n'ai pas touché à la --iptables o --icc options.

5voto

Sylvain Points 740

UPDATE : Bien que cette réponse soit toujours valable, la réponse de @SystemParadox qui utilise DOCKER-USER en combinaison avec --ctorigdstport est meilleur.

Voici une solution qui persiste bien entre les redémarrages et qui permet d'affecter les exposée plutôt que le port interno port.

iptables -t mangle -N DOCKER-mysql
iptables -t mangle -A DOCKER-mysql -s 22.33.44.144/32 -j RETURN
iptables -t mangle -A DOCKER-mysql -s 22.33.44.233/32 -j RETURN
iptables -t mangle -A DOCKER-mysql -j DROP
iptables -t mangle -A PREROUTING -i eth0 -p tcp -m tcp --dport 3306 -j DOCKER-mysql

J'ai construit une image Docker qui utilise cette méthode pour gérer automatiquement les iptables pour vous, en utilisant soit des variables d'environnement, soit dynamiquement avec etcd (ou les deux) :

https://hub.docker.com/r/colinmollenhour/confd-firewall/

2voto

easycheese Points 111

En m'appuyant sur l'excellente réponse acceptée de @SystemParadox, j'ai voulu prévenir todos le trafic (TCP et UDP) de todos des hôtes externes vers les ports publiés de todos puisque je vais faire du reverse proxying sur les ports des conteneurs auxquels je veux accéder de l'extérieur.

La règle qui m'a permis d'atteindre cet objectif :

iptables -I DOCKER-USER -i eth0 -m conntrack --ctdir ORIGINAL -j DROP

Cela permet d'insérer la règle en haut de la page DOCKER-USER chaîne. Ajustez en conséquence avec le(s) nom(s) réel(s) de votre (vos) interface(s) réseau externe(s), ou les positions souhaitées dans la chaîne (avec -I DOCKER-USER <number> ).

En conntrack module avec ctdir semble être important ici, car j'ai eu quelques problèmes avec les docker-compose d perdent l'accès au monde extérieur avec des variantes que j'ai essayées sans elles. Par exemple : iptables -I DOCKER-USER -i eth0 ! -s 127.0.0.1 -j DROP suggéré par Jeff Geerling dans un article de blog à partir de 2020, elle-même issue de les documents officiels Le système de gestion de l'information a empêché mes conteneurs de communiquer avec des adresses IP externes.

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X