Bloquer l’accès depuis l’extérieur aux conteneurs Docker (Linux)

Docker est très pratique pour lancer des services hétéroclites sur un serveur sans trop de problèmes de conflits entre eux (Nginx et Apache par exemple). Mais, par défaut, Docker expose ces services sur un port de la machine hôte, donc accessible depuis l’extérieur.
Si comme moi vous voulez plus de contrôle sur quels port sont accessibles ou simplement que vous voulez utiliser un reverse proxy devant (pour utiliser un domaine par exemple), il est possible de fermer l’accès direct aux services Docker par défaut à coups de quelques règles iptables. Voyons comment faire.
Les IPTables
Pour rappel avant de commencer, les IPTables sont un méchanisme dans Linux qui permet d’appliquer des filtres sur le traffic réseau entrant, sortant ou transféré entre deux interfaces, c’est un pare-feu.
Si les IPTables ne sont pas très claires pour vous je vous conseille la lecture ce cet article avant de commencer.
Par défaut Docker mets en place des règles permettant d’accéder aux services sur l’interface docker0 par transfert de paquets depuis n’importe quelle autre interface. On va donc aller ce placer en amont de ces règles pour filtrer le trafic, ça permet de ne pas modifier le config de docker et de conserver les règles pour atteindre les services depuis la machine hôte.
Bloquer tout le traffic
Pour commencer on va créer une nouvelle table PRE_DOCKER pour contenir nos règles.
iptables -N PRE_DOCKEROn définit ensuite l’action par défaut de cette table : pour cela on insert une règle dans notre nouvelle table sans conditions et avec l’actionDROP
iptables -I PRE_DOCKER -j DROPOn ajoute ensuite des exceptions pour le traffic “normal” de Docker :
- Le traffic entre les conteneurs
- Le traffic de Docker vers l’extérieur
- Les connexions déjà établies ou liées à une autre
Ce qui donne
iptables -I PRE_DOCKER -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -I PRE_DOCKER -i docker0 ! -o docker0 -j ACCEPT
iptables -I PRE_DOCKER -m state --state RELATED -j ACCEPT
iptables -I PRE_DOCKER -i docker0 -o docker0 -j ACCEPTIl ne reste plus maintenant qu’à insérer notre table dans une chaîne. Dans notre cas il s’agit de la chaîne FORWARD car le traffic de l’extérieur vers Docker arrive sur une interface et est transféré vers l’interface de Docker docker0
iptables -I FORWARD -o docker0 -j PRE_DOCKERAutoriser quelques services
Si on veut autoriser quelques service à être accessible depuis l’extérieur, il faut rajouter des règles dans notre table de filtrage.
La méthode que je propose permet d’accéder à tous les services qui écoutent sur le même port. Si vous démarrez deux conteneurs Nginx, les deux écoutent sur le port 80 et sont redirigés sur deux ports différents de la machine hôte par Docker. Avec cette méthode les deux seront autorisés avec une seul règle. Il ne pourront pas être dissociés.
C’est un comportement qui me va. Si vous n’êtes pas dans ce cas là je vous invite à creuser les iptables.
Du coup on autorise le port d’écoute du conteneur par le port de destination de la machine cible !
Par exemple pour un conteneur écoutant sur le port 80 (tcp)
iptables -I PRE_DOCKER -p tcp --dport 80 -j ACCEPTJ’en ai fini avec cette petite astuce. J’ai écris un petit script bash pour gagner du temps qui exécute la partie blocage. Il dispo ici.
A+

