Solution 1 :
Après avoir passé quelques jours à examiner les journaux et les configurations des composants concernés, j'étais sur le point de jeter l'éponge et de revenir à Fedora 30, où cela semble fonctionner dès la sortie de la boîte.
En me concentrant sur le pare-feu, j'ai réalisé que la désactivation de firewalld
semblait faire l'affaire, mais je préférerais ne pas le faire. Lors de l'inspection des règles du réseau avec iptables
, j'ai réalisé que le passage à nftables
signifie que iptables
est maintenant une couche d'abstraction qui ne montre qu'une petite partie du nftables
règles. Cela signifie la plupart - sinon la totalité - des firewalld
la configuration sera appliquée en dehors du champ d'application de iptables
.
J'avais l'habitude de pouvoir trouver toute la vérité dans iptables
, il faudra donc un certain temps pour s'y habituer.
Pour faire court - pour que cela fonctionne, je devais activer le masquage. Cela ressemblait à dockerd
déjà fait cela via iptables
, mais apparemment, cela doit être spécifiquement activé pour la zone de pare-feu pour iptables
se faire passer pour travailler :
# Masquerading allows for docker ingress and egress (this is the juicy bit)
firewall-cmd --zone=public --add-masquerade --permanent
# Specifically allow incoming traffic on port 80/443 (nothing new here)
firewall-cmd --zone=public --add-port=80/tcp
firewall-cmd --zone=public --add-port=443/tcp
# Reload firewall to apply permanent rules
firewall-cmd --reload
Redémarrez ou redémarrez dockerd
, et l'entrée et la sortie devraient fonctionner.
Solution 2 :
Ce qui manque dans les réponses précédentes, c'est le fait que vous devez d'abord ajouter votre interface docker à la zone que vous configurez, par ex. public (ou ajoutez-le à la zone "de confiance" qui a été suggérée ici mais je doute que ce soit sage, du point de vue de la sécurité). Parce que par défaut, il n'est pas affecté à une zone. N'oubliez pas également de recharger le démon docker lorsque vous avez terminé.
# Check what interface docker is using, e.g. 'docker0'
ip link show
# Check available firewalld zones, e.g. 'public'
sudo firewall-cmd --get-active-zones
# Check what zone the docker interface it bound to, most likely 'no zone' yet
sudo firewall-cmd --get-zone-of-interface=docker0
# So add the 'docker0' interface to the 'public' zone. Changes will be visible only after firewalld reload
sudo nmcli connection modify docker0 connection.zone public
# Masquerading allows for docker ingress and egress (this is the juicy bit)
sudo firewall-cmd --zone=public --add-masquerade --permanent
# Optional open required incomming ports (wasn't required in my tests)
# sudo firewall-cmd --zone=public --add-port=443/tcp
# Reload firewalld
sudo firewall-cmd --reload
# Reload dockerd
sudo systemctl restart docker
# Test ping and DNS works:
docker run busybox ping -c 1 172.16.0.1
docker run busybox cat /etc/resolv.conf
docker run busybox ping -c 1 yourhost.local
Solution 3 :
Pour pouvoir définir des règles précises pour Docker, je n'ai pas eu besoin de définir docker0 sur une zone.
# 1. Stop Docker
systemctl stop docker
# 2. Recreate DOCKER-USER chain in firewalld.
firewall-cmd --permanent \
--direct \
--remove-chain ipv4 filter DOCKER-USER
firewall-cmd --permanent \
--direct \
--remove-rules ipv4 filter DOCKER-USER
firewall-cmd --permanent \
--direct \
--add-chain ipv4 filter DOCKER-USER
# (Ignore any warnings)
# 3. Docker Container <-> Container communication
firewall-cmd --permanent \
--direct \
--add-rule ipv4 filter DOCKER-USER 1 \
-m conntrack --ctstate RELATED,ESTABLISHED \
-j ACCEPT \
-m comment \
--comment 'Allow docker containers to connect to the outside world'
firewall-cmd --permanent \
--direct \
--add-rule ipv4 filter DOCKER-USER 1 \
-j RETURN \
-s 172.17.0.0/16 \
-m comment \
--comment 'allow internal docker communication'
# Change the Docker Subnet to your actual one (e.g. 172.18.0.0/16)
# 4. Add rules for IPs allowed to access the Docker exposed ports.
firewall-cmd --permanent \
--direct \
--add-rule ipv4 filter DOCKER-USER 1 \
-o docker0 \
-p tcp \
-m multiport \
--dports 80,443 \
-i eth0 \
-o docker0 \
-s 1.2.3.4/32 \
-j ACCEPT \
-m comment \
--comment 'Allow IP 1.2.3.4 to docker ports 80 and 443'
# 5. log docker traffic (if you like)
firewall-cmd --direct \
--add-rule ipv4 filter DOCKER-USER 0 \
-j LOG \
--log-prefix ' DOCKER: '
# 6. Block all other IPs.
This rule has lowest precedence, so you can add allowed IP rules later.
firewall-cmd --permanent \
--direct \
--add-rule ipv4 filter DOCKER-USER 10 \
-j REJECT \
-m comment \
--comment 'reject all other traffic to DOCKER-USER'
# 7. Reload firewalld, Start Docker again
firewall-cmd --reload
systemctl start docker
Cela se termine par des règles définies dans /etc/firewalld/direct.xml :
<?xml version="1.0" encoding="utf-8"?>
<direct>
<chain ipv="ipv4" table="filter" chain="DOCKER-USER"/>
<rule ipv="ipv4" table="filter" chain="DOCKER-USER" priority="0">-m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -m comment --comment 'Allow docker containers to connect to the outside world'</rule>
<rule ipv="ipv4" table="filter" chain="DOCKER-USER" priority="0">-j RETURN -s 172.17.0.0/16 -m comment --comment 'allow internal docker communication'</rule>
<rule ipv="ipv4" table="filter" chain="DOCKER-USER" priority="0">-p tcp -m multiport --dports 80,443 -s 1.2.3.4/32 -j ACCEPT -m comment --comment 'Allow IP 1.2.3.4 to docker ports 80 and 443'</rule>
<rule ipv="ipv4" table="filter" chain="DOCKER-USER" priority="0">-j LOG --log-prefix ' DOCKER TCP: '</rule>
<rule ipv="ipv4" table="filter" chain="DOCKER-USER" priority="10">-j REJECT -m comment --comment 'reject all other traffic to DOCKER-USER'</rule>
</direct>
L'inconvénient est que vous devez installer containerd.io à partir de CentOS7 comme indiqué par Saustrup