From 339c08c5c2dc361aee8172326afcb70d539951a9 Mon Sep 17 00:00:00 2001 From: Rasmus Wejlgaard Date: Sun, 29 Mar 2026 09:07:42 +0000 Subject: [PATCH] Configure UFW firewall rules in common Ansible role Add UFW configuration to the common role for Debian hosts: - Default deny incoming, allow outgoing - Allow all traffic on tailscale0 interface (mesh comms) - Allow SSH port 22 as safety net - Per-host allowed ports via ufw_allowed_ports variable - Enable UFW after rules are applied helsinki-a gets ports 80/443 for reverse proxy traffic. Other Debian hosts only need Tailscale + SSH. Closes PESO-79 --- ansible/inventory/host_vars/helsinki-a.yml | 4 ++ ansible/inventory/host_vars/nuremberg-a.yml | 2 + ansible/roles/common/defaults/main.yml | 7 +++ ansible/roles/common/handlers/main.yml | 4 ++ ansible/roles/common/tasks/main.yml | 62 +++++++++++++++++++++ 5 files changed, 79 insertions(+) create mode 100644 ansible/roles/common/defaults/main.yml diff --git a/ansible/inventory/host_vars/helsinki-a.yml b/ansible/inventory/host_vars/helsinki-a.yml index 3dd4849..418aee7 100644 --- a/ansible/inventory/host_vars/helsinki-a.yml +++ b/ansible/inventory/host_vars/helsinki-a.yml @@ -9,3 +9,7 @@ docker_services: - authelia - forgejo - bitwarden + +ufw_allowed_ports: + - { port: 80, proto: tcp, comment: "HTTP" } + - { port: 443, proto: tcp, comment: "HTTPS" } diff --git a/ansible/inventory/host_vars/nuremberg-a.yml b/ansible/inventory/host_vars/nuremberg-a.yml index 07f69bd..2061d0d 100644 --- a/ansible/inventory/host_vars/nuremberg-a.yml +++ b/ansible/inventory/host_vars/nuremberg-a.yml @@ -3,3 +3,5 @@ host_role: mail host_description: "Mail server (poste.io)" host_location: "Hetzner Cloud" ansible_python_interpreter: /usr/bin/python3 +# NOTE: Alpine host — UFW tasks are Debian-only. +# Firewall rules for mail ports (25,465,587,993,143,80,443) managed separately. diff --git a/ansible/roles/common/defaults/main.yml b/ansible/roles/common/defaults/main.yml new file mode 100644 index 0000000..8249b70 --- /dev/null +++ b/ansible/roles/common/defaults/main.yml @@ -0,0 +1,7 @@ +--- +# UFW firewall defaults +# Override ufw_allowed_ports in host_vars for public-facing services. +ufw_enabled: true +ufw_allowed_ports: [] +# - { port: 80, proto: tcp, comment: "HTTP" } +# - { port: 443, proto: tcp, comment: "HTTPS" } diff --git a/ansible/roles/common/handlers/main.yml b/ansible/roles/common/handlers/main.yml index 6998953..350609b 100644 --- a/ansible/roles/common/handlers/main.yml +++ b/ansible/roles/common/handlers/main.yml @@ -3,3 +3,7 @@ ansible.builtin.service: name: sshd state: restarted + +- name: Reload ufw + community.general.ufw: + state: reloaded diff --git a/ansible/roles/common/tasks/main.yml b/ansible/roles/common/tasks/main.yml index 06f2d0a..9cde5e2 100644 --- a/ansible/roles/common/tasks/main.yml +++ b/ansible/roles/common/tasks/main.yml @@ -100,3 +100,65 @@ state: started enabled: true when: ansible_facts["os_family"] == "Debian" + +# --- UFW firewall (Debian only) --- + +- name: Set UFW default deny incoming + community.general.ufw: + direction: incoming + default: deny + when: + - ansible_facts["os_family"] == "Debian" + - ufw_enabled | bool + notify: Reload ufw + +- name: Set UFW default allow outgoing + community.general.ufw: + direction: outgoing + default: allow + when: + - ansible_facts["os_family"] == "Debian" + - ufw_enabled | bool + notify: Reload ufw + +- name: Allow all traffic on Tailscale interface + community.general.ufw: + rule: allow + interface_or_direction: in + interface: tailscale0 + comment: "Tailscale mesh - allow all" + when: + - ansible_facts["os_family"] == "Debian" + - ufw_enabled | bool + notify: Reload ufw + +- name: Allow SSH (safety net) + community.general.ufw: + rule: allow + port: '22' + proto: tcp + comment: "SSH" + when: + - ansible_facts["os_family"] == "Debian" + - ufw_enabled | bool + notify: Reload ufw + +- name: Allow host-specific ports + community.general.ufw: + rule: allow + port: "{{ item.port | string }}" + proto: "{{ item.proto | default('tcp') }}" + comment: "{{ item.comment | default(omit) }}" + loop: "{{ ufw_allowed_ports }}" + when: + - ansible_facts["os_family"] == "Debian" + - ufw_enabled | bool + - ufw_allowed_ports | length > 0 + notify: Reload ufw + +- name: Enable UFW + community.general.ufw: + state: enabled + when: + - ansible_facts["os_family"] == "Debian" + - ufw_enabled | bool