From 6ced9cbcfabda1bfeb7374da6b989b15214bb043 Mon Sep 17 00:00:00 2001 From: Ludovic Cartier Date: Wed, 27 May 2026 19:13:33 +0200 Subject: [PATCH] handle docker rules & templatize custom rules --- README.md | 38 +++++++++++--------- defaults/main.yml | 4 +++ templates/firewall.j2 | 80 +++++++++++++++++++++++++++++++++++-------- 3 files changed, 91 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 4be3420..6980de3 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ Role Ansible pour déployer un pare-feu iptables/ip6tables via un script shell e Variables par défaut dans [defaults/main.yml](defaults/main.yml). - firewall_public_interface: interface publique pour les logs optionnels. Si null, utilise ansible_default_ipv4.interface. +- firewall_docker_safe: préserve les chaînes Docker lors d'un restart du firewall. - firewall_admin_sources: liste des CIDR autorisés sur les services admin. - firewall_admin_rules_ipv4: liste des règles IPv4 limitées aux sources admin. - firewall_public_tcp_ports_ipv4: ports TCP IPv4 ouverts publiquement. @@ -29,39 +30,42 @@ Variables par défaut dans [defaults/main.yml](defaults/main.yml). ```yaml firewall_admin_sources: - - cidr: "203.0.113.10/32" - comment: "bastion" + - cidr: "203.0.113.10/32" + comment: "bastion" + +firewall_docker_safe: true firewall_admin_rules_ipv4: - - proto: "udp" - dport: 51820 - comment: "wireguard" - - proto: "tcp" - dport: 22 - comment: "ssh admin" + - proto: "udp" + dport: 51820 + comment: "wireguard" + - proto: "tcp" + dport: 22 + comment: "ssh admin" firewall_public_tcp_ports_ipv4: - - 22 - - 80 - - 443 + - 22 + - 80 + - 443 firewall_public_tcp_ports_ipv6: - - 80 - - 443 + - 80 + - 443 ``` ## Exemple de playbook ```yaml - name: Configure firewall - hosts: all - become: true - roles: - - role: firewall + hosts: all + become: true + roles: + - role: firewall ``` ## Notes - Le script applique une politique restrictive (DROP sur INPUT/OUTPUT/FORWARD) puis ouvre explicitement les flux requis. - Toute erreur de syntaxe shell du template est validée avant déploiement via /bin/sh -n. +- En mode docker-safe, les chaînes Docker existantes sont préservées pour éviter de casser la connectivité des conteneurs au restart. diff --git a/defaults/main.yml b/defaults/main.yml index ce2caea..5a28c4d 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -3,6 +3,10 @@ # If null, ansible_default_ipv4.interface is used. firewall_public_interface: null +# Preserve Docker-managed chains/rules when restarting the firewall. +# When true, FORWARD chain is not reset if Docker chains are detected. +firewall_docker_safe: true + # IPv4 source networks allowed to access admin-restricted services. firewall_admin_sources: - cidr: "51.158.69.165/32" diff --git a/templates/firewall.j2 b/templates/firewall.j2 index 86c09da..ee9a555 100644 --- a/templates/firewall.j2 +++ b/templates/firewall.j2 @@ -11,6 +11,7 @@ NAME=firewall DESC="packet filter" PUBIF="{{ firewall_public_interface | default(ansible_default_ipv4.interface | default('eth0')) }}" +FIREWALL_DOCKER_SAFE="{{ firewall_docker_safe | default(true) | ternary('1', '0') }}" #PRIVATEIF=eth1 case "$1" in @@ -18,10 +19,28 @@ case "$1" in echo -n "Initializing $DESC. \n" ### IPv4 ### echo " \033[33mIPv4 : \033[0m" + + HAS_DOCKER4=0 + if [ "$FIREWALL_DOCKER_SAFE" = "1" ] && $IPT4 -S DOCKER >/dev/null 2>&1; then + HAS_DOCKER4=1 + fi + + # Reset only chains managed by this role. + $IPT4 -F INPUT + $IPT4 -F OUTPUT + $IPT4 -F ADMIN >/dev/null 2>&1 || true + $IPT4 -X ADMIN >/dev/null 2>&1 || true + + if [ "$HAS_DOCKER4" -eq 0 ]; then + $IPT4 -F FORWARD + $IPT4 -P FORWARD DROP + else + echo " * Docker detected, preserving IPv4 FORWARD chain : \033[32m[OK] \033[0m" + fi + # DROP all incomming traffic $IPT4 -P INPUT DROP $IPT4 -P OUTPUT DROP - $IPT4 -P FORWARD DROP echo " * Deny all input and output IPv4 connections : \033[32m[OK] \033[0m" # Unlimited access to loopback @@ -67,10 +86,26 @@ case "$1" in ### IPv6 ### echo " \033[33mIPv6 : \033[0m" + + HAS_DOCKER6=0 + if [ "$FIREWALL_DOCKER_SAFE" = "1" ] && $IPT6 -S DOCKER >/dev/null 2>&1; then + HAS_DOCKER6=1 + fi + + # Reset only chains managed by this role. + $IPT6 -F INPUT + $IPT6 -F OUTPUT + + if [ "$HAS_DOCKER6" -eq 0 ]; then + $IPT6 -F FORWARD + $IPT6 -P FORWARD DROP + else + echo " * Docker detected, preserving IPv6 FORWARD chain : \033[32m[OK] \033[0m" + fi + # DROP all incomming traffic $IPT6 -P INPUT DROP $IPT6 -P OUTPUT DROP - $IPT6 -P FORWARD DROP echo " * Deny all input and output IPv6 connections : \033[32m[OK] \033[0m" # Unlimited access to loopback @@ -112,26 +147,43 @@ case "$1" in stop) echo -n "Resetting $DESC. \n" + + HAS_DOCKER4=0 + if [ "$FIREWALL_DOCKER_SAFE" = "1" ] && $IPT4 -S DOCKER >/dev/null 2>&1; then + HAS_DOCKER4=1 + fi + + HAS_DOCKER6=0 + if [ "$FIREWALL_DOCKER_SAFE" = "1" ] && $IPT6 -S DOCKER >/dev/null 2>&1; then + HAS_DOCKER6=1 + fi + ### IPv4 ### - $IPT4 -F - $IPT4 -X - $IPT4 -P FORWARD ACCEPT + $IPT4 -F INPUT + $IPT4 -F OUTPUT + $IPT4 -F ADMIN >/dev/null 2>&1 || true + $IPT4 -X ADMIN >/dev/null 2>&1 || true + if [ "$HAS_DOCKER4" -eq 0 ]; then + $IPT4 -F FORWARD + $IPT4 -P FORWARD ACCEPT + else + echo " * Docker detected, preserving IPv4 FORWARD chain : \033[32m[OK] \033[0m" + fi $IPT4 -P INPUT ACCEPT $IPT4 -P OUTPUT ACCEPT - $IPT4 -t nat -F - $IPT4 -t nat -X - $IPT4 -t mangle -F - $IPT4 -t mangle -X echo " * Cleaning IPv4 chains and rules : \033[32m[OK] \033[0m" ### IPv6 ### - $IPT6 -F - $IPT6 -X - $IPT6 -P FORWARD ACCEPT + $IPT6 -F INPUT + $IPT6 -F OUTPUT + if [ "$HAS_DOCKER6" -eq 0 ]; then + $IPT6 -F FORWARD + $IPT6 -P FORWARD ACCEPT + else + echo " * Docker detected, preserving IPv6 FORWARD chain : \033[32m[OK] \033[0m" + fi $IPT6 -P INPUT ACCEPT $IPT6 -P OUTPUT ACCEPT - $IPT6 -t mangle -F - $IPT6 -t mangle -X echo " * Cleaning IPv6 chains and rules : \033[32m[OK] \033[0m" echo ;;