Docker fout un beau bordel avec les règles iptables/nftables, et voici pourquoi ça fait vraiment chier :


🚨 Ce que Docker fait par défaut :

  1. Il modifie directement iptables/nftables sans te demander ton avis.

  2. Il crée ses propres chaînes (DOCKER, DOCKER-USER, etc.) un peu partout.

  3. Il suppose que tu veux que tout conteneur ait accès à tout.

  4. Il te colle des règles MASQUERADE (NAT source) qui passent au-dessus de ta logique.

  5. Et surtout : il fonctionne mal avec des firewalls personnalisés ou stricts — ce qui est précisément ton cas.


💣 Ce que ça cause :

  • Conflits avec tes règles manuelles (FORWARD DROP, etc.)

  • Des comportements “magiques” impossibles à tracer (ça marche pour curl, mais pas pour SMTP, etc.)

  • Des trous de sécurité si tu oublies de tout verrouiller ensuite


Solutions concrètes

1. Désactiver la gestion automatique du firewall par Docker

Ajoute ceci à /etc/docker/daemon.json :

                {
  "iptables": false,
  "ip6tables": false
}

              

Puis :

                sudo systemctl restart docker

              

🛑 Attention : Docker ne créera plus aucune règle. Tu dois tout gérer toi-même — ce qui est parfait pour toi.


2. Créer tes propres règles nftables pour gérer Docker proprement

Par exemple :

                table inet filter {
  chain default_fwd {
    type filter hook forward priority filter; policy drop;

    iifname "docker0" oifname != "docker0" accept
    iifname "br-8203e51da77b" oifname != "br-8203e51da77b" accept
    oifname "docker0" ct state related,established accept
    oifname "br-8203e51da77b" ct state related,established accept
  }
}

              

Tu peux être aussi précis que tu veux : destination, port, protocole, interface, groupe de conteneurs, etc.


3. Ou carrément isoler les conteneurs et passer par un reverse proxy/NAT filtré

Tu les colles sur un bridge privé, puis tu exposes uniquement ce que tu veux avec des règles de NAT explicites et propres. Fini le fouillis.


Plan détaillé et complet de ton pare-feu nftables de production, avec :

  • 🔒 Politique par défaut DROP

  • 🌐 Accès web nginx (ports 80/443)

  • 🐳 Accès total à Internet pour les containers Docker (docker0, br-*)

  • 🛡️ Filtrage global (blackhole sets)

  • 🧠 Fail2Ban avec f2b-table

  • 📄 Logs pertinents dans un fichier séparé avec rsyslog et rotation

  • 🔁 Masquerading NAT pour Docker

  • 💾 Chargement via /etc/nftables.conf et démarrage automatique


🔧 1. Fichier nftables.conf (à placer dans /etc/nftables.conf)

                #!/usr/sbin/nft -f

flush ruleset

table inet filter {
  set blackhole_v4 {
    type ipv4_addr
    flags interval
  }

  set blackhole_v6 {
    type ipv6_addr
    flags interval
  }

  chain global {
    ip saddr @blackhole_v4 drop
    ip daddr @blackhole_v4 drop
    ip6 saddr @blackhole_v6 drop
    ip6 daddr @blackhole_v6 drop
  }

  chain INPUT {
    type filter hook input priority 0; policy drop;

    iifname "lo" accept
    ct state established,related accept
    ct state invalid drop

    jump global

    # Web
    tcp dport { 80, 443 } accept

    # SSH
    tcp dport 22 accept

    # Fail2Ban
    ip saddr @addr-set-sshd tcp dport 22 reject
    ip saddr @addr-set-nextcloud tcp dport { 80, 443 } reject

    # ICMP
    ip protocol icmp accept
    ip6 nexthdr ipv6-icmp accept

    # log rejet
    log prefix "[nftables] INPUT DROP: " flags all level warning
    counter reject
  }

  chain OUTPUT {
    type filter hook output priority 0; policy drop;

    oifname "lo" accept
    ct state established,related accept
    ct state invalid drop

    jump global

    # par défaut : open bar
    accept
  }

  chain FORWARD {
    type filter hook forward priority 0; policy drop;

    jump global
    jump docker_fwd

    # log rejet
    log prefix "[nftables] FORWARD DROP: " flags all level warning
    counter reject
  }

  chain docker_fwd {
    # Containers vers Internet
    iifname "docker0" oifname != "docker0" accept
    iifname "br-+" oifname != "br-+" accept

    # Réponses vers containers
    ct state related,established accept
  }
}

table inet f2b-table {
  set addr-set-sshd {
    type ipv4_addr
    flags interval
  }

  set addr-set-nextcloud {
    type ipv4_addr
    flags interval
  }

  chain INPUT {
    type filter hook input priority -1; policy accept;
    tcp dport 22 ip saddr @addr-set-sshd reject
    tcp dport { 80, 443 } ip saddr @addr-set-nextcloud reject
  }
}

table ip nat {
  chain POSTROUTING {
    type nat hook postrouting priority srcnat; policy accept;

    # NAT Docker vers Internet (IP de l'hôte)
    ip saddr 172.17.0.0/16 masquerade
    ip saddr 172.18.0.0/16 masquerade
  }
}

              

📝 2. Log vers fichier dédié avec rsyslog

Fichier : /etc/rsyslog.d/30-nftables.conf

                :msg, contains, "[nftables]" /var/log/nftables.log
& stop

              

Puis :

                sudo touch /var/log/nftables.log
sudo chmod 640 /var/log/nftables.log
sudo systemctl restart rsyslog

              

🔁 3. Rotation des logs

Fichier : /etc/logrotate.d/nftables

                /var/log/nftables.log {
  weekly
  rotate 4
  compress
  delaycompress
  missingok
  notifempty
  create 640 syslog adm
  postrotate
    /bin/systemctl restart rsyslog > /dev/null 2>&1 || true
  endscript
}

              

🚀 4. Activer nftables au boot

                sudo systemctl enable nftables
sudo systemctl restart nftables

              

✅ 5. Vérification

                sudo nft list ruleset
sudo ip a | grep docker

              

Tu peux aussi tester depuis une VM Docker :

                docker run --rm -it alpine sh
apk add curl
curl https://example.com

              

Et SMTP :

                apk add busybox-extras
telnet smtp.koumbit.net 587
              



Une bonne manière d'attirer l'attention de vos lecteurs est de raconter une histoire.
Tout ce que vous considérez écrire peut être raconté comme une histoire.