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?
docker run -d -p 3306:3306 mysql
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!
Deux choses à garder à l'esprit lorsque vous travaillez avec les règles de pare-feu de Docker:
DOCKER-USER
chaînePREROUTING
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.
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.
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):
[~ # ~] 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.