Question Étapes à suivre pour limiter les connexions extérieures au 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? Comprenant uniquement les bases d'iptables avec les options par défaut de Docker, je trouve cela très difficile.

Je souhaite exécuter un conteneur, le rendre visible pour l'Internet public, mais n'autoriser que les connexions à partir d'hôtes sélectionnés. Je m'attendrais à définir une stratégie d'entrée par défaut de REJECT et à n'autoriser ensuite que les connexions à partir de mes hôtes. Mais les règles et chaînes NAT de Docker gênent et mes règles INPUT sont ignorées.

Quelqu'un peut-il donner un exemple de la façon d'atteindre mon objectif compte tenu des hypothèses suivantes?

  • Hôte IP public 80.80.80.80 sur eth0
  • Host privé IP 192.168.1.10 sur eth1
  • docker run -d -p 3306:3306 mysql
  • Bloquer toutes les connexions à l'hôte / 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 au processus de menu fixe et au redémarrage de l'hôte.

Merci!


11
2017-07-09 14:36


origine




Réponses:


Deux choses à garder à l’esprit lorsque vous travaillez avec les règles de pare-feu de docker:

  1. Pour éviter que vos règles soient gâchées par un menu fixe, utilisez la commande DOCKER-USER chaîne
  2. Docker fait le mappage de port dans le PREROUTING chaîne de nat table. Cela se passe avant le filter règles, donc --dest et --dport verra l'IP interne et le port 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 -j ACCEPT
iptables -A DOCKER-USER -i eth0 -s 4.4.4.4 -p tcp -m conntrack --ctorigdstport 3306 -j ACCEPT
iptables -A DOCKER-USER -i eth0 -p tcp -m conntrack --ctorigdstport 3306 -j DROP

1
2017-10-03 16:05



Cela devrait être la réponse acceptée! - ColinM


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

Les règles de transfert de Docker autorisent par défaut toutes les adresses IP de sources externes. Pour autoriser uniquement un IP ou un réseau spécifique à accéder aux conteneurs, insérez une règle inversée en haut de la chaîne de filtres DOCKER. Par exemple, pour limiter l'accès externe de telle sorte que seule l'IP source 8.8.8.8 puisse accéder aux conteneurs, vous pouvez ajouter la règle suivante: iptables -I DOCKER -i ext_if ! -s 8.8.8.8 -j DROP

Ce que j'ai fini par faire était:

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é le --iptables ou --icc options.


5
2017-07-09 22:17



Si tu fais iptables -vnL DOCKER, les ports de destination sont tous des ports du conteneur. Si je comprends bien, cela signifie que les règles ci-dessus n’affecteront que le port 3306 dans le conteneur - c'est-à-dire, si vous deviez -p 12345:3306 votre conteneur, votre règle serait encore être celui qui est nécessaire pour verrouiller l'accès (c.-à-d. --dport 12345 ne fonctionnerait pas), car les règles ACCEPT de la chaîne DOCKER sont post-NAT. - sunside
C'est vrai, les règles doivent se rapporter aux ports dans les conteneurs. - GGGforce
Hum, c'est un peu moche si vous utilisez plusieurs conteneurs qui utilisent, par exemple, un NGINX interne pour effectuer un proxy inverse (par exemple, Zabbix, un équilibreur de charge personnalisé, etc.), car vous devez connaître à l'avance l'adresse IP du conteneur. Je cherche toujours une solution à ce problème qui ne nécessite pas --iptables=false, parce que cela semble être le pire choix de tous. - sunside
Je vous remercie! Vous avez résolu mon problème après de nombreuses heures de recherche. Maintenant, je peux enfin emprisonner MySQL juste à l'adresse IP de mon domicile sans exposer le ventre mou au monde entier. - Matt Cavanagh


Avec Docker v.17.06, il existe une nouvelle chaîne iptables appelée DOCKER-USER. Celui-ci est pour vos règles personnalisées: https://docs.docker.com/engine/userguide/networking/#docker-and-iptables

Contrairement à la chaîne DOCKER, elle n'est pas réinitialisée sur les conteneurs de construction / de démarrage. Vous pouvez donc ajouter ces lignes à votre configuration / script iptables pour le provisioning du 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 pense qu’il ouvre le port au monde entier. (Ces règles supposent que votre interface externe est eth0.)

Finalement, vous devrez nettoyer iptables, redémarrez d’abord le service Docker, si vous l’avez mal gâté en essayant de verrouiller le port comme je l’ai fait.


5
2017-12-02 10:56



Je ne comprends pas pourquoi cette table DOCKER-USER est différente de toute autre table ajoutée par l'utilisateur. Elle n'a pas de filtre pré-appliqué, vous devez donc toujours spécifier vous-même les noms d'interface. Si vous créez un "MY-CHAIN" et l'insérez dans la chaîne FORWARD, le résultat sera identique, non? - ColinM
Oui, cela fait une différence, car Docker insère la chaîne DOCKER-USER dans la chaîne FORWARD: -A FORWARD -j DOCKER-USER  -A FORWARD -j DOCKER-ISOLATION      C'est pourquoi les instructions personnalisées sont exécutées avant la chaîne DOCKER. - ck1
Notez que si vous utilisez --dport dans DOCKER-USER, cela doit correspondre à la interne IP du service de conteneur, ne pas le port exposé. Celles-ci correspondent souvent, mais pas toujours, et cela pourrait facilement entrer en conflit avec d'autres services. Je soutiens donc que cette solution DOCKER-USER est à moitié cuite. - ColinM


METTRE À JOUR: Bien que cette réponse soit toujours valide, la réponse de @SystemParadox en utilisant DOCKER-USER en combinaison avec --ctorigdstportest mieux.

Voici une solution qui persiste bien entre les redémarrages et vous permet d’affecter le exposé port plutôt que le interne 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 des variables d'environnement ou de manière dynamique avec etcd (ou les deux):

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


3
2017-12-07 16:22