firewalld Zones and Rich Rules: Safe Configuration - 夜莺博客

firewalld Zones and Rich Rules: Safe Configuration

firewalld is not a flat rule list, and treating it like one is why so many engineers lock themselves out of a remote host. Every packet is matched to exactly one zone, that zone decides what is allowed, and there are two parallel configurations — runtime and permanent — that must both be updated. This guide covers the zone model, the precedence rules, and the rich-rule syntax you need for source-scoped access, rate limiting and logging.

The zone model

A zone is a named policy bucket. Each active network interface is in exactly one zone, and a packet is matched to a zone by this precedence, first match wins:

  1. Source address — if the packet's source IP is in a subnet bound to a zone, that zone is used regardless of the arriving interface. Source bindings are the most specific match.
  2. Interface — otherwise the zone bound to the arriving interface is used.
  3. Default zone — if neither matches, the packet lands in the default zone, which is public on a fresh install.

Predefined zones range from drop and block (most restrictive) through public, internal, home and dmz to trusted, which accepts everything. On modern distributions firewalld translates zone configuration into nftables rules underneath, so the concepts transpose directly if you already think in nftables.

Runtime versus permanent

This is the single biggest source of confusion:

  • Runtime — active immediately in the kernel, lost on firewall-cmd --reload or reboot.
  • Permanent — stored in XML under /etc/firewalld/, loaded at startup or after a reload, but it does not affect the running kernel until you reload.

A command without --permanent changes only runtime; a command with --permanent changes only the on-disk configuration. Forgetting one half produces a rule that works until reboot, or a rule that is saved but never applied. The safe workflow is: test at runtime, confirm, then repeat with --permanent and --reload.

sudo firewall-cmd --runtime-to-permanent   # capture everything currently running
sudo firewall-cmd --permanent --zone=public --list-all
sudo firewall-cmd --zone=public --list-all

Comparing the two listings is the fastest way to catch a missing reload.

Zone and interface administration

firewall-cmd --state
firewall-cmd --get-default-zone
firewall-cmd --get-active-zones
firewall-cmd --get-zone-of-interface=eth1
firewall-cmd --list-all-zones

sudo firewall-cmd --permanent --zone=internal --change-interface=eth1
sudo firewall-cmd --reload
firewall-cmd --get-active-zones

Assigning the zone through NetworkManager persists it in the connection profile, which survives firewalld restarts without a separate permanent change:

nmcli connection modify "Wired connection 1" connection.zone internal
nmcli connection up "Wired connection 1"

Services, ports and rich rules

sudo firewall-cmd --get-services
sudo firewall-cmd --permanent --zone=public --add-service=https
sudo firewall-cmd --permanent --zone=public --add-port=8080/tcp
sudo firewall-cmd --reload

Rich rules express what service and port entries cannot: source scoping, logging, rate limiting, reject type and priority.

# allow a management port only from one subnet
sudo firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="192.168.10.0/24" port port="5432" protocol="tcp" accept'

# rate-limit SSH to blunt brute force
sudo firewall-cmd --permanent --zone=public --add-rich-rule='rule service name="ssh" limit value="3/m" accept'

# log and reject telnet attempts
sudo firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" port port="23" protocol="tcp" log prefix="TELNET-ATTEMPT" level="warning" reject'

sudo firewall-cmd --reload
sudo firewall-cmd --zone=public --list-rich-rules

Two behaviours worth internalising: firewalld echoes a rich rule back exactly as parsed, so a rule that reads back malformed was never stored correctly; and a reject or drop rich rule takes precedence over an accept for the same match, so a broad drop with a high priority number will shadow your allows.

Not locking yourself out

  1. Before editing, confirm ssh is in the services list of the zone your management interface uses: firewall-cmd --zone=public --list-services.
  2. Apply new rules at runtime first and keep the session open.
  3. Test a brand-new session from a separate terminal or host.
  4. Only then run the same commands with --permanent and --reload.
  5. If you do lock yourself out, a scheduled systemd-run or at job that restores /etc/firewalld/ and reloads is the standard rescue pattern — set it up before you need it.

For troubleshooting, rich-rule drops appear in the kernel log: journalctl -k | grep DROPPED.

See also: nftables stateful firewall and conntrack, nftables NAT and port forwarding, and hardening the OpenSSH server.

原文链接:https://linuxjunkies.org/guides/configure-firewalld-zones