From 94ed0f08fe3104a2cf14e6f17edd7e77268a5100 Mon Sep 17 00:00:00 2001 From: Marcus Weiner Date: Mon, 4 Dec 2023 22:53:40 +0100 Subject: [PATCH] Refactor firewall to use nftables (#2) * Refactor firewall to use nftables * Fix module name * Avoid running the nftables role twice * Fix invalid subnet definition * Fix invalid nftables rule --- roles/gateway/handlers/main.yaml | 6 +++--- roles/gateway/tasks/main.yaml | 24 ++++++----------------- roles/gateway/templates/firewall.nft.j2 | 22 +++++++++++++++++++++ roles/gateway/templates/firewall.v4.j2 | 16 --------------- roles/gateway/templates/firewall.v6.j2 | 6 ------ roles/nftables/handlers/main.yaml | 4 ++++ roles/nftables/tasks/main.yaml | 26 +++++++++++++++++++++++++ site.yml | 1 + 8 files changed, 62 insertions(+), 43 deletions(-) create mode 100644 roles/gateway/templates/firewall.nft.j2 delete mode 100644 roles/gateway/templates/firewall.v4.j2 delete mode 100644 roles/gateway/templates/firewall.v6.j2 create mode 100644 roles/nftables/handlers/main.yaml create mode 100644 roles/nftables/tasks/main.yaml diff --git a/roles/gateway/handlers/main.yaml b/roles/gateway/handlers/main.yaml index 353e0ad..5be9a89 100644 --- a/roles/gateway/handlers/main.yaml +++ b/roles/gateway/handlers/main.yaml @@ -8,7 +8,7 @@ name: dnsmasq state: restarted -- name: restart netfilter-persistent +- name: reload nftables ansible.builtin.service: - name: netfilter-persistent - state: restarted + name: nftables + state: reloaded diff --git a/roles/gateway/tasks/main.yaml b/roles/gateway/tasks/main.yaml index 7b5f575..072c51f 100644 --- a/roles/gateway/tasks/main.yaml +++ b/roles/gateway/tasks/main.yaml @@ -24,25 +24,13 @@ dest: /etc/dnsmasq.conf notify: restart dnsmasq -- name: Install firewall helper +- name: (cleanup) Uninstall firewall helper ansible.builtin.package: name: iptables-persistent - state: present - -- name: Configure IPv4 firewall rules - ansible.builtin.template: - src: firewall.v4.j2 - dest: /etc/iptables/rules.v4 - notify: restart netfilter-persistent + state: absent -- name: Configure IPv6 firewall rules +- name: Configure firewall rules ansible.builtin.template: - src: firewall.v6.j2 - dest: /etc/iptables/rules.v6 - notify: restart netfilter-persistent - -- name: Enable firewall helper - ansible.builtin.service: - name: netfilter-persistent - state: started - enabled: true + src: firewall.nft.j2 + dest: /etc/nftables.d/firewall.nft + notify: reload nftables diff --git a/roles/gateway/templates/firewall.nft.j2 b/roles/gateway/templates/firewall.nft.j2 new file mode 100644 index 0000000..0ac5c86 --- /dev/null +++ b/roles/gateway/templates/firewall.nft.j2 @@ -0,0 +1,22 @@ +define client_subnet = {{ gateway_ipv4_address | ansible.utils.ipaddr('network/prefix') }} + +table inet filter { + chain forward { + type filter hook forward priority 0; policy drop; + + # reject SMTP + tcp dport 25 reject with icmp type port-unreachable + + # limit routed traffic to ip subnet + iif br0 ip saddr $client_subnet accept + oif br0 ip daddr $client_subnet accept + } +} + +table inet nat { + chain postrouting { + type nat hook postrouting priority 0; + + ip saddr $client_subnet oif eth0 snat to {{ service_ipv4_address | ipaddr('address') }} + } +} diff --git a/roles/gateway/templates/firewall.v4.j2 b/roles/gateway/templates/firewall.v4.j2 deleted file mode 100644 index 8d80567..0000000 --- a/roles/gateway/templates/firewall.v4.j2 +++ /dev/null @@ -1,16 +0,0 @@ -*filter -:INPUT ACCEPT [0:0] -:FORWARD DROP [0:0] -:OUTPUT ACCEPT [0:0] --A FORWARD -p tcp -m tcp --dport 25 -j REJECT --reject-with icmp-port-unreachable --A FORWARD -s {{ gateway_ipv4_address | ipaddr('net') }} -i br0 -j ACCEPT --A FORWARD -d {{ gateway_ipv4_address | ipaddr('net') }} -o br0 -j ACCEPT -COMMIT - -*nat -:PREROUTING ACCEPT [0:0] -:INPUT ACCEPT [0:0] -:OUTPUT ACCEPT [0:0] -:POSTROUTING ACCEPT [0:0] --A POSTROUTING -s {{ gateway_ipv4_address | ipaddr('net') }} -o eth0 -j SNAT --to-source {{ service_ipv4_address | ipaddr('address') }} -COMMIT diff --git a/roles/gateway/templates/firewall.v6.j2 b/roles/gateway/templates/firewall.v6.j2 deleted file mode 100644 index 4578e1f..0000000 --- a/roles/gateway/templates/firewall.v6.j2 +++ /dev/null @@ -1,6 +0,0 @@ -*filter -:INPUT ACCEPT [0:0] -:FORWARD DROP [0:0] -:OUTPUT ACCEPT [0:0] --A FORWARD -p tcp -m tcp --dport 25 -j REJECT --reject-with icmp6-port-unreachable -COMMIT diff --git a/roles/nftables/handlers/main.yaml b/roles/nftables/handlers/main.yaml new file mode 100644 index 0000000..11a411d --- /dev/null +++ b/roles/nftables/handlers/main.yaml @@ -0,0 +1,4 @@ +- name: reload nftables + ansible.builtin.service: + name: nftables + state: reloaded diff --git a/roles/nftables/tasks/main.yaml b/roles/nftables/tasks/main.yaml new file mode 100644 index 0000000..b7b6340 --- /dev/null +++ b/roles/nftables/tasks/main.yaml @@ -0,0 +1,26 @@ +- name: Install nftables + ansible.builtin.package: + name: nftables + state: present + +- name: Uninstall iptables + ansible.builtin.package: + name: iptables + state: absent + +- name: Create rule dir + ansible.builtin.file: + path: /etc/nftables.d + state: directory + +- name: Setup rule loading + ansible.builtin.lineinfile: + path: /etc/nftables.conf + line: include "/etc/nftables.d/*" + notify: reload nftables + +- name: Enable rule loading + ansible.builtin.service: + name: nftables + state: started + enabled: true diff --git a/site.yml b/site.yml index 48dfcb5..fe374d6 100644 --- a/site.yml +++ b/site.yml @@ -3,6 +3,7 @@ become: true roles: - { role: kernel-full, tags: kernel-full } + - { role: nftables, tags: nftables } - { role: service-ip, tags: service-ip } - { role: fastd, tags: fastd } - { role: batman, tags: batman }