À coup sûr vous l’aurez compris, Iptables va avoir un rôle. Mais avant d’en arriver à cela, reprenons la construction d’un nouveau réseau virtuel docker.
Par défaut, les réseaux docker sont au nombre de 3 [2]:
$ docker network ls NETWORK ID NAME DRIVER SCOPE ff147d84a29e bridge bridge local 8932db1d0751 host host local 9a54dab98d45 none null local
Ces trois types de réseau sont gérés par trois drivers spécifiques:
- le driver null permettant d’isoler complètement les conteneurs qui serait associé à ce réseau en ne lui ne leur associant aucune adresse ip.
- le drivers host qui permet de partager l’interface réseau de la machine hôte avec les conteneurs associé à ce réseau.
- le driver bridge qui permet ici de construire une nouvelle interface réseau sur la machine hôte (un bridge entre autre! [3])
Essayons [docker-networking]:
$ docker network create net-test d4aaba91e629e5b7f1cf14f81a2f8ce279307579430280c67fe081ebecef0c39 $ docker network inspect net-test [ { "Name": "net-test", "Id": "d4aaba91e629e5b7f1cf14f81a2f8ce279307579430280c67fe081ebecef0c39", "Created": "2019-11-23T17:18:36.467168945+01:00", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": {}, "Config": [ { "Subnet": "172.20.0.0/16", "Gateway": "172.20.0.1" } ] }, "Internal": false, "Attachable": false, "Ingress": false, "ConfigFrom": { "Network": "" }, "ConfigOnly": false, "Containers": {}, "Options": {}, "Labels": {} } ]
Ainsi avec docker inspect on constate que la gateway qui à ete construit est en 172.20.0.1
Si on regarde du coté de la conf réseau de la machine hote:
$ ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group [...] 17: br-d4aaba91e629: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default link/ether 02:42:a6:9d:11:87 brd ff:ff:ff:ff:ff:ff inet 172.20.0.1/16 brd 172.20.255.255 scope global br-d4aaba91e629 valid_lft forever preferred_lft forever
Effectivement maintenant on à un bridge mais côté iptables il n’y pas grand chose à voir en dehors de la conf de base docker car nous n’avons aucun conteneur dans ce reseau.
Pour y voir plus clair considérons le docker-compose suivant:
version: "3.2"
services:
tc-registry:
image: registry:2.7.1
ports:
- 5000:5000
Le lancement de ce containeur va alors constuire par defaut un reseau dedié avec un bridge (ici nommé tc-infra-base_default), et une adresse reseau dedié au conteneur. Voyons cela:
$ docker-compose up -d tc-registry Creating network "tc-infra-base_default" with the default driver Creating tc-infra-base_tc-registry_1 ... done
Si on inspect ce reseau qu’avons nous:
$ docker network inspect tc-infra-base_default [ { "Name": "tc-infra-base_default", "Id": "c43bef5f1b354c45bc32179a2184002ec91fa21a2686199deae24eacccdbcdff", "Created": "2019-11-23T17:32:01.141824783+01:00", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": null, "Config": [ { "Subnet": "172.21.0.0/16", "Gateway": "172.21.0.1" } ] }, "Internal": false, "Attachable": true, "Ingress": false, "ConfigFrom": { "Network": "" }, "ConfigOnly": false, "Containers": { "68d130ea5de4fab1dedf61a8c026bf19e8b90f9d28cdd16268e874a9f46558c5": { "Name": "tc-infra-base_tc-registry_1", "EndpointID": "c4133255d2a0d9a546d54bf3d8491dcc62990aca5d2ceeb2b32c0a051dba2f3a", "MacAddress": "02:42:ac:15:00:02", "IPv4Address": "172.21.0.2/16", "IPv6Address": "" } }, "Options": {}, "Labels": { "com.docker.compose.network": "default", "com.docker.compose.project": "tc-infra-base" } } ]
On retrouve ici une gateway en 172.21.0.1 et on constate egelement que la conteneur de la registry à elle aussi une adresse ip dans le reseau 172.21.0.0, c’est à dire 172.21.0.2
Maintenant que nous avons un conteneur dans le reseau, regardons du coté de iptables ce que cela implique.
Du coté de la table nat:
$ sudo iptables -t nat -L Chain PREROUTING (policy ACCEPT) target prot opt source destination DOCKER all -- anywhere anywhere ADDRTYPE match dst-type LOCAL Chain INPUT (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination DOCKER all -- anywhere !localhost/8 ADDRTYPE match dst-type LOCAL Chain POSTROUTING (policy ACCEPT) target prot opt source destination MASQUERADE all -- 172.21.0.0/16 anywhere MASQUERADE all -- 172.17.0.0/16 anywhere MASQUERADE tcp -- 172.21.0.2 172.21.0.2 tcp dpt:5000 Chain DOCKER (2 references) target prot opt source destination RETURN all -- anywhere anywhere RETURN all -- anywhere anywhere DNAT tcp -- anywhere anywhere tcp dpt:5000 to:172.21.0.2:5000
On voit que notre réseau existe ici POSTROUTING à côté du réseau docker par défaut (le bridge par défaut sur le réseau en 172.17.0.0). Également une règle DNAT est appliqué afin de router les trames vers le conteneur.
Du côté de la table filter:
$ sudo iptables -t filter -L Chain INPUT (policy ACCEPT) target prot opt source destination Chain FORWARD (policy DROP) target prot opt source destination DOCKER-USER all -- anywhere anywhere DOCKER-ISOLATION-STAGE-1 all -- anywhere anywhere ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED DOCKER all -- anywhere anywhere ACCEPT all -- anywhere anywhere ACCEPT all -- anywhere anywhere ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED DOCKER all -- anywhere anywhere 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.21.0.2 tcp dpt:5000 Chain DOCKER-ISOLATION-STAGE-1 (1 references) target prot opt source destination DOCKER-ISOLATION-STAGE-2 all -- anywhere anywhere DOCKER-ISOLATION-STAGE-2 all -- anywhere anywhere RETURN all -- anywhere anywhere Chain DOCKER-ISOLATION-STAGE-2 (2 references) target prot opt source destination DROP all -- anywhere anywhere DROP all -- anywhere anywhere RETURN all -- anywhere anywhere Chain DOCKER-USER (1 references) target prot opt source destination RETURN all -- anywhere anywhere
Dans cette table on constate la présence des règles d’isolation permettant de consolider le sous réseau. De même il y à une règle permettant d’autoriser (ACCEPT dans la chain DOCKER) les trames à être transmisent au conteneur.
Conclusions
La gestion des réseaux dans docker est un incontournable pour bénéficier de toute la puissance cet outil. A l’inverse, celle de iptable ne l’est heureusement pas.Pourtant pour une utilisation avancé de docker, il est important de mesurer au combien docker masque énormément d'élément de complexité.
Avec cet article, le but était d’explorer (et encore plutôt en surface) ce point toujours assez mystérieux de la gestion réseau dans docker.
Références:
[1] https://un-est-tout-et-tout-est-un.blogspot.com/2019/10/reseau-iptables-routeur-logiciel.html[2] https://stackoverflow.com/questions/41083328/what-is-the-use-of-host-and-none-network-in-docker
[3] https://fr.wikipedia.org/wiki/Pont_(r%C3%A9seau)
[docker-networking] https://success.docker.com/article/networking
[iptables-docker] https://docs.docker.com/network/iptables/
Aucun commentaire:
Enregistrer un commentaire