web-dev-qa-db-fra.com

Étapes pour limiter les connexions externes au conteneur Docker avec iptables?

Mon objectif est de limiter l'accès aux conteneurs Docker à seulement quelques adresses IP publiques. Existe-t-il un processus simple et reproductible pour atteindre mon objectif? Comprendre uniquement les bases d'iptables lors de l'utilisation des options par défaut de Docker, je trouve cela très difficile.

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

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

  • Hôte 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 toute connexion à l'hôte/conteneur 3306 sauf à partir des hôtes 4.4.4.4 et 8.8.8.8

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

Merci!

23
GGGforce

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 encombrées par le docker, utilisez le DOCKER-USER chaîne
  2. Docker effectue le mappage de port dans la chaîne PREROUTING de la table nat. Cela se produit avant les règles filter, 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 --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

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

20
SystemParadox

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/network/iptables/

Contrairement à la chaîne DOCKER, elle n'est pas réinitialisée lors de la construction/démarrage des conteneurs. Vous pouvez donc ajouter ces lignes à votre configuration/script iptables 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. (Ces règles supposent que votre interface externe est eth0.)

Finalement, vous devrez d'abord nettoyer iptables, redémarrer le service docker, si vous l'avez trop gâché en essayant de verrouiller le port comme je l'ai fait.

8
ck1

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

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

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/

4
ColinM

[~ # ~] mise à jour [~ # ~] : Bien que valide en 2015, cette solution n'est plus la bonne façon de le faire.

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

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

J'ai fini par faire:

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.

4
GGGforce