firewalld Role Usage Guide
The firewalld role manages firewalld zones declaratively by writing zone XML files to /etc/firewalld/zones/. Any zone file on the host that is not represented in firewalld_zones is deleted on the next run, making zone configuration fully version-controlled.
Platform support
| OS | Packages installed |
|---|---|
| RHEL / Rocky | firewalld, at (via dnf) |
| Ubuntu / Debian | firewalld, at (via apt) |
Calling the role
The role accepts a single variable: firewalld_zones. Pass it via include_role:
- name: Configure firewall
ansible.builtin.include_role:
name: firewalld
vars:
firewalld_zones:
public:
target: DROP
services:
- https
- ssh
ports:
- "7327"
monitoring:
target: DROP
sources:
- 10.248.5.0/24
services:
- ssh
ports:
- "9113"
- "9100"
Zone types
firewalld routes traffic to a zone based on the first match:
Source-based zones — a zone with one or more entries in sources receives traffic originating from those CIDRs. This is how a monitoring zone restricts Prometheus scrapes to a specific subnet without affecting other traffic.
Interface-based zones — a zone with no sources is assigned to a network interface (or is the default zone). The public zone is typically the OS default and receives all traffic not matched by a source-based zone.
Lockout protection
Every run of the role takes the following steps to prevent accidental SSH lockout:
- Backup — copies the current zone directory to
/tmp/firewalld_zones_backup - Schedule revert — schedules an
atjob to fire in 2 minutes that restores the backup and reloads firewalld - Apply changes — writes new zone XML files, removes any extras, reloads firewalld
- Verify connectivity — runs
wait_for_connection(60-second timeout) to confirm the controller can still reach the host via SSH - Cancel revert — if connectivity is confirmed, cancels the
atjob and removes all artifacts
If step 4 fails (SSH is blocked), two recovery paths exist:
- In-band rescue (ControlMaster socket available from prior connections): the rescue block runs immediately, restoring the backup and reloading firewalld before the
atjob fires - At-job revert (no existing connection): the
atjob fires after 2 minutes, restoring the backup. The revert script is idempotent — if the rescue block already ran and cleaned up the backup, the at job exits without making changes
In both cases, all temporary artifacts (/tmp/firewall_revert.sh, /tmp/firewall_revert_job_id, /tmp/firewalld_zones_backup) are removed before the run ends.
Verifying firewall state
# Show which zones are active (have an interface or source binding)
firewall-cmd --get-active-zones
# List configuration for a specific zone
firewall-cmd --zone=public --list-all
firewall-cmd --zone=monitoring --list-all
# Show all zones (including those with no active bindings)
firewall-cmd --list-all-zones
# Show the zone files on disk
ls -la /etc/firewalld/zones/