diff --git a/roles/base/tasks/firewall.yml b/roles/base/tasks/firewall.yml index 58885cc..dc8b2d0 100644 --- a/roles/base/tasks/firewall.yml +++ b/roles/base/tasks/firewall.yml @@ -28,3 +28,67 @@ validate: "nft -c -f %s" register: base__firewall_render tags: [firewall] + +- name: Apply firewall ruleset safely (with auto-rollback) + when: + - base__firewall_apply | bool + - base__firewall_render is changed + tags: [firewall] + block: + - name: Snapshot the current ruleset as the rollback point + ansible.builtin.shell: "nft list ruleset > /etc/nftables.rollback" + changed_when: false + + - name: Stop stale rollback timer unit + ansible.builtin.systemd: + name: "{{ item }}" + state: stopped + loop: + - nft-rollback.timer + - nft-rollback.service + failed_when: false + changed_when: false + + - name: Reset failed state on stale rollback units + ansible.builtin.command: systemctl reset-failed {{ item }} + loop: + - nft-rollback.timer + - nft-rollback.service + failed_when: false + changed_when: false + + - name: Arm the auto-rollback timer + ansible.builtin.command: + cmd: >- + systemd-run --on-active={{ base__firewall_rollback_timeout }} + --unit=nft-rollback /usr/sbin/nft -f /etc/nftables.rollback + changed_when: true + + - name: Apply the new ruleset + ansible.builtin.command: nft -f /etc/nftables.conf + changed_when: true + + - name: Stop the rollback timer after connectivity confirmed + ansible.builtin.systemd: + name: "{{ item }}" + state: stopped + loop: + - nft-rollback.timer + - nft-rollback.service + failed_when: false + changed_when: false + + - name: Reset failed state on rollback units after disarm + ansible.builtin.command: systemctl reset-failed {{ item }} + loop: + - nft-rollback.timer + - nft-rollback.service + failed_when: false + changed_when: false + +- name: Enable nftables.service so the ruleset persists across reboot + ansible.builtin.systemd: + name: nftables + enabled: true + when: base__firewall_apply | bool + tags: [firewall]