From 3c751af3ce4f7652c96436178209aa345a27745b Mon Sep 17 00:00:00 2001 From: "Rasmus \"Pez\" Wejlgaard" Date: Thu, 2 Apr 2026 21:18:11 +0100 Subject: [PATCH] fix(firewall_alpine): replace empty iptables ruleset with proper INPUT filtering (#32) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Bind node_exporter to Tailscale IP on public-facing hosts node_exporter was listening on 0.0.0.0:9100 on helsinki-a and london-a, exposing metrics to the public internet. Changes: - Add node_exporter_bind_tailscale flag (default false) to opt in - Set flag on helsinki-a and london-a host_vars - Debian: configure ARGS in /etc/default/prometheus-node-exporter - FreeBSD: use native node_exporter_listen_address rc.conf variable - Add handlers to restart on config change Prometheus already scrapes via Tailscale IPs, no scrape config changes needed. Fixes PESO-98 * fix(firewall_alpine): replace empty iptables ruleset with proper INPUT filtering The rules.v4.j2 template deployed a ruleset with INPUT ACCEPT and zero custom rules — effectively a no-op. nuremberg-a is a public-facing mail server and needs actual filtering. Changes: - INPUT default policy set to DROP - Allow loopback, established/related, Tailscale interface, SSH, ICMP - FORWARD stays ACCEPT for Docker port-forwarding - Added firewall_alpine_extra_input_rules variable for host-specific rules Mail ports remain handled by Docker's FORWARD chain, not INPUT. Closes PESO-119 --- .../firewall_alpine/templates/rules.v4.j2 | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/ansible/roles/firewall_alpine/templates/rules.v4.j2 b/ansible/roles/firewall_alpine/templates/rules.v4.j2 index 5182207..9468d96 100644 --- a/ansible/roles/firewall_alpine/templates/rules.v4.j2 +++ b/ansible/roles/firewall_alpine/templates/rules.v4.j2 @@ -2,13 +2,32 @@ # iptables rules for {{ inventory_hostname }} # # Docker and Tailscale manage their own chains automatically. -# This file captures non-Docker, non-Tailscale rules only. +# This file captures non-Docker, non-Tailscale INPUT rules only. # # Mail ports (25,80,110,143,443,465,587,993,995) are exposed via -# Docker port mappings in the poste-io docker-compose.yml — not here. +# Docker port mappings — traffic goes through FORWARD, not INPUT. *filter -:INPUT ACCEPT [0:0] +:INPUT DROP [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] + +# Allow loopback +-A INPUT -i lo -j ACCEPT + +# Allow established and related connections +-A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT + +# Allow all traffic on Tailscale interface +-A INPUT -i tailscale0 -j ACCEPT + +# Allow SSH (public access — fail2ban provides brute-force protection) +-A INPUT -p tcp --dport 22 -j ACCEPT + +# Allow ICMP (ping) +-A INPUT -p icmp -j ACCEPT + +{% for rule in firewall_alpine_extra_input_rules | default([]) %} +{{ rule }} +{% endfor %} COMMIT