Docker
Iptables avec Docker
Recherche…
Introduction
Cette rubrique explique comment limiter l'accès à vos conteneurs de docker du monde extérieur à l'aide d'iptables.
Pour les personnes impatientes, vous pouvez consulter les exemples. Pour les autres, veuillez lire la section des remarques pour comprendre comment construire de nouvelles règles.
Syntaxe
- iptables -I DOCKER [RULE ...] [ACCEPT | DROP] // Pour ajouter une règle en haut de la table DOCKER
- iptables -D DOCKER [RULE ...] [ACCEPT | DROP] // Pour supprimer une règle de la table DOCKER
- ipset restore </etc/ipfriends.conf // Pour reconfigurer vos ipfriends ipset
Paramètres
Paramètres | Détails |
---|---|
ext_if | Votre interface externe sur l'hôte Docker. |
XXX.XXX.XXX.XXX | Une adresse IP particulière sur laquelle les conteneurs Docker doivent être accessibles. |
AAAA.AAAA.AAAA.AAAA | Une autre adresse IP sur laquelle les conteneurs Docker doivent être accessibles doit être fournie. |
ipfriends | Le nom de l'ipset définissant les adresses IP autorisées à accéder à vos conteneurs Docker. |
Remarques
Le problème
La configuration des règles iptables pour les conteneurs Docker est un peu délicate. Au début, vous penseriez que les règles de pare-feu "classiques" devraient faire l'affaire.
Par exemple, supposons que vous avez configuré un conteneur nginx-proxy + plusieurs conteneurs de services pour exposer via HTTPS certains services Web personnels. Ensuite, une règle comme celle-ci devrait donner accès à vos services Web uniquement pour IP XXX.XXX.XXX.XXX.
$ iptables -A INPUT -i eth0 -p tcp -s XXX.XXX.XXX.XXX -j ACCEPT
$ iptables -P INPUT DROP
Cela ne marchera pas, vos conteneurs sont toujours accessibles pour tout le monde.
En effet, les conteneurs Docker ne sont pas des services hôtes. Ils s'appuient sur un réseau virtuel dans votre hôte et l'hôte agit comme une passerelle pour ce réseau. Et en ce qui concerne les passerelles, le trafic routé n'est pas géré par la table INPUT, mais par la table FORWARD, ce qui rend la règle affichée avant qu'elle soit inefficace.
Mais ce n'est pas tout. En fait, le démon Docker crée beaucoup de règles iptables quand il commence à faire sa magie concernant la connectivité réseau des conteneurs. En particulier, une table DOCKER est créée pour gérer les règles concernant les conteneurs en transférant le trafic de la table FORWARD vers cette nouvelle table.
$ iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy DROP)
target prot opt source destination
DOCKER-ISOLATION all -- anywhere anywhere
DOCKER all -- anywhere anywhere
ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED
ACCEPT all -- anywhere anywhere
ACCEPT all -- anywhere anywhere
DOCKER all -- anywhere anywhere
ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED
ACCEPT all -- anywhere anywhere
ACCEPT all -- anywhere anywhere
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Chain DOCKER (2 references)
target prot opt source destination
ACCEPT tcp -- anywhere 172.18.0.4 tcp dpt:https
ACCEPT tcp -- anywhere 172.18.0.4 tcp dpt:http
Chain DOCKER-ISOLATION (1 references)
target prot opt source destination
DROP all -- anywhere anywhere
DROP all -- anywhere anywhere
RETURN all -- anywhere anywhere
La solution
Si vous consultez la documentation officielle ( https://docs.docker.com/v1.5/articles/networking/) , une première solution est proposée pour limiter l'accès du conteneur Docker à une adresse IP particulière.
$ iptables -I DOCKER -i ext_if ! -s 8.8.8.8 -j DROP
En effet, ajouter une règle en haut de la table DOCKER est une bonne idée. Cela n'interfère pas avec les règles configurées automatiquement par Docker, et c'est simple. Mais deux grands manques:
- Tout d'abord, que faire si vous avez besoin d'accéder à deux adresses IP au lieu d'une seule? Ici, une seule IP src peut être acceptée, les autres seront supprimées sans aucun moyen de prévention.
- Deuxièmement, que se passe-t-il si votre docker doit avoir accès à Internet? Dans la pratique, aucune requête ne réussira car seul le serveur 8.8.8.8 pourra y répondre.
- Enfin, que faire si vous souhaitez ajouter d'autres logiques? Par exemple, donnez accès à n'importe quel utilisateur à votre serveur Web utilisant le protocole HTTP, mais limitez tout le reste à une adresse IP particulière.
Pour la première observation, nous pouvons utiliser ipset . Au lieu d'autoriser une IP dans la règle ci-dessus, nous autorisons toutes les IP de l'ipset prédéfini. En prime, l'ipset peut être mis à jour sans qu'il soit nécessaire de redéfinir la règle iptable.
$ iptables -I DOCKER -i ext_if -m set ! --match-set my-ipset src -j DROP
Pour la seconde observation, il s'agit d'un problème canonique pour les pare-feu: si vous êtes autorisé à contacter un serveur via un pare-feu, le pare-feu doit autoriser le serveur à répondre à votre demande. Cela peut être fait en autorisant des paquets liés à une connexion établie. Pour la logique du docker, cela donne:
$ iptables -I DOCKER -i ext_if -m state --state ESTABLISHED,RELATED -j ACCEPT
La dernière observation porte sur un point: les règles iptables sont essentielles. En effet, une logique supplémentaire pour ACCEPTER certaines connexions (y compris celle concernant les connexions ESTABLISHED) doit être placée en haut de la table DOCKER, avant la règle DROP qui refuse toutes les connexions restantes ne correspondant pas à l'ipset.
Comme nous utilisons l'option -I d'iptable, qui insère des règles en haut de la table, les règles iptables précédentes doivent être insérées par ordre inverse:
// Drop rule for non matching IPs
$ iptables -I DOCKER -i ext_if -m set ! --match-set my-ipset src -j DROP
// Then Accept rules for established connections
$ iptables -I DOCKER -i ext_if -m state --state ESTABLISHED,RELATED -j ACCEPT
$ iptables -I DOCKER -i ext_if ... ACCEPT // Then 3rd custom accept rule
$ iptables -I DOCKER -i ext_if ... ACCEPT // Then 2nd custom accept rule
$ iptables -I DOCKER -i ext_if ... ACCEPT // Then 1st custom accept rule
En gardant cela à l'esprit, vous pouvez maintenant vérifier les exemples qui illustrent cette configuration.
Limiter l'accès aux conteneurs Docker à un ensemble d'IP
D'abord, installez ipset si nécessaire. Veuillez vous référer à votre distribution pour savoir comment le faire. À titre d'exemple, voici la commande pour les distributions de type Debian.
$ apt-get update
$ apt-get install ipset
Créez ensuite un fichier de configuration pour définir un ipset contenant les adresses IP pour lesquelles vous souhaitez ouvrir l'accès à vos conteneurs Docker.
$ vi /etc/ipfriends.conf
# Recreate the ipset if needed, and flush all entries
create -exist ipfriends hash:ip family inet hashsize 1024 maxelem 65536
flush
# Give access to specific ips
add ipfriends XXX.XXX.XXX.XXX
add ipfriends YYY.YYY.YYY.YYY
Chargez cet ipset.
$ ipset restore < /etc/ipfriends.conf
Assurez-vous que votre démon Docker est en cours d'exécution: aucune erreur ne doit apparaître après la saisie de la commande suivante.
$ docker ps
Vous êtes prêt à insérer vos règles iptables. Vous devez respecter la commande.
// All requests of src ips not matching the ones from ipset ipfriends will be dropped.
$ iptables -I DOCKER -i ext_if -m set ! --match-set ipfriends src -j DROP
// Except for requests coming from a connection already established.
$ iptables -I DOCKER -i ext_if -m state --state ESTABLISHED,RELATED -j ACCEPT
Si vous souhaitez créer de nouvelles règles, vous devrez supprimer toutes les règles personnalisées que vous avez ajoutées avant d'insérer les nouvelles.
$ iptables -D DOCKER -i ext_if -m set ! --match-set ipfriends src -j DROP
$ iptables -D DOCKER -i ext_if -m state --state ESTABLISHED,RELATED -j ACCEPT
Configurez l'accès aux restrictions au démarrage du démon Docker
Travaux en cours
Quelques règles iptables personnalisées
Travaux en cours