Home / Alt manpages / firewalld.policy(5)

  • firewalld.policy(5)
  • File format
  • linux

Write a firewalld Policy XML File and Verify It

Zones alone cannot express "internal may talk out to external, but only on HTTPS and DNS", and that gap is what firewalld policies fill. This guide builds a small permanent policy file, checks it, reloads firewalld and confirms the policy is visible. The example uses firewalld 2.1.1, installed here as package version 2.1.1-1, and takes about 20 minutes.

  • You need root access, firewalld installed, and two existing zones whose names match your network design.
  • Risk. This changes the host firewall and can interrupt traffic after the reload.
  • Keep a session open. Hold an existing root or console session while you test.

1. Check the installed contract

Read the local manual page and identify the command paths before editing anything. These are ordinary, read-only commands:

$ man firewalld.policy
$ firewall-cmd --version
FirewallD is not running
$ dpkg-query -W -f='${Package} ${Version}\n' firewalld
firewalld 2.1.1-1

The version command can print a warning when the daemon is stopped. That is not a version mismatch. The package query is the useful version check on this Debian-style system; on another distribution, use its package tool instead.

A few facts about policy files:

  • Naming. A policy file is named policy_name.xml. The installed manual limits policy_name to 17 characters, so this guide uses lab-egress.
  • Location. Host-specific policy files belong in /etc/firewalld/policies. Files in /usr/lib/firewalld/policies are supplied defaults.
  • Why /etc. A package update will not overwrite your changes there.

Confirm the directory and the zones you intend to connect:

$ sudo install -d -m 0755 /etc/firewalld/policies
$ firewall-cmd --get-zones
block dmz drop external home internal public trusted work

Checkpoint

The directory exists and the zone list contains the two zones you plan to use. The zone output is host-specific, so replace internal and external below only if your host uses different existing zone names. A policy is directional: ingress internal to egress external is not the reverse direction.

2. Save the current policy state

Before a privileged change, check whether this policy already exists and keep any file with the same name. The commands below read the configuration and create a recoverable backup:

$ sudo test -e /etc/firewalld/policies/lab-egress.xml && \
    sudo cp --preserve=all /etc/firewalld/policies/lab-egress.xml \
    /etc/firewalld/policies/lab-egress.xml.bak || true
$ sudo ls -l /etc/firewalld/policies

If the file already exists, inspect the backup before you carry on. Do not overwrite an unfamiliar production policy just to make this example fit. If you decide not to continue, remove only the backup you just made after confirming its path, or leave it for later recovery.

3. Write the policy XML

Now create the policy as root. This is the first state-changing step. The XML has one policy element, two zone bindings and two port entries. CONTINUE is the default target, so packets that do not match these entries are left for the rest of firewalld's policy evaluation.

$ sudo tee /etc/firewalld/policies/lab-egress.xml >/dev/null <<'XML'
<?xml version="1.0" encoding="utf-8"?>
<policy target="CONTINUE">
  <short>Lab egress</short>
  <description>Allow web and DNS traffic from the internal lab to the external zone.</description>
  <ingress-zone name="internal"/>
  <egress-zone name="external"/>
  <port port="443" protocol="tcp"/>
  <port port="53" protocol="udp"/>
</policy>
XML
$ sudo sed -n '1,80p' /etc/firewalld/policies/lab-egress.xml
  • tee needs elevation because the destination is under /etc.
  • The quoted heredoc marker stops the shell expanding the XML text.
  • The port entries are explicit. The local manual allows TCP, UDP, SCTP and DCCP for this element, and a port can be a number or a range.

Checkpoint

The sed output is the same XML you supplied. If the file is empty or truncated, stop and restore the backup before doing anything that reloads firewalld.

4. Check before reloading

Ask firewalld to check its permanent configuration. This is read-only with respect to the running rules, but it may need root access to read all the configuration files:

$ sudo firewall-cmd --check-config
success

If it reports an XML or policy error, do not reload. Check these:

  • Closing tags. Every element closed properly.
  • Zone names. Both spelt exactly as --get-zones shows them.
  • Name length. The policy name is within the 17-character limit.
  • Protocol values. Valid protocols on each port entry.

A valid XML document can still describe a policy that matches no traffic if its zone bindings are wrong.

Checkpoint

Continue only after you see success. A non-zero exit status means the configuration is not ready for activation.

5. Reload and inspect the active policy

Warning

Reloading is the second state-changing step and can briefly disrupt connections. Run it during a suitable maintenance window.

$ sudo firewall-cmd --reload
success
$ firewall-cmd --get-policies
lab-egress
$ firewall-cmd --policy=lab-egress --list-ingress-zones
internal
$ firewall-cmd --policy=lab-egress --list-egress-zones
external
$ firewall-cmd --policy=lab-egress --list-ports
443:tcp 53:udp

The exact ordering and whitespace can differ. What matters is that lab-egress is listed, both zone bindings are present, and both ports appear. If a command reports that the daemon is not running, start or enable firewalld according to your distribution's service policy before treating that as a policy-file error.

These checks confirm that firewalld loaded the policy. They do not prove that an application can reach a particular host. Test from a machine in the ingress zone, using a destination and route that really belong to the egress zone. A connection test can also be affected by the destination service, routing, DNS or another policy.

6. Roll back safely

Warning

Warn users or operators before rolling back, because the reload can again interrupt connections.

If this example replaced an existing file, restore its backup. If it was a new file, remove only this policy file:

$ if sudo test -e /etc/firewalld/policies/lab-egress.xml.bak; then
    sudo cp --preserve=all /etc/firewalld/policies/lab-egress.xml.bak \
      /etc/firewalld/policies/lab-egress.xml
  else
    sudo rm -- /etc/firewalld/policies/lab-egress.xml
  fi
$ sudo firewall-cmd --check-config
$ sudo firewall-cmd --reload

Do not use a broad recursive removal under /etc/firewalld. The backup copy is the undo path for an existing policy. Once the restored configuration has been checked and reloaded, verify that firewall-cmd --get-policies no longer shows the temporary policy if it was newly created.

Common traps

  • Packaged defaults are not for overrides. A file under /usr/lib/firewalld/policies is a packaged default, not the normal place for a local override.
  • Zones give the scope. A policy without matching ingress and egress zones has no useful traffic scope. The direction is not inferred from the port.
  • CONTINUE is not a blanket rule. target="CONTINUE" is neither allow nor deny. Use the policy's rules and the rest of the firewall configuration to understand unmatched traffic.
  • Editing is not applying. Changing the XML does not change the running firewall until firewalld reloads it. Conversely, a runtime change made through firewall-cmd may not be the file you are inspecting.
  • Do not swap in a terminal target casually. ACCEPT, REJECT or DROP in place of CONTINUE decides what happens to unmatched packets in the policy and can block traffic beyond the two examples above.

Done means

  • Version and syntax checked. You checked the installed firewalld version and the local firewalld.policy(5) syntax.
  • Name and place are right. The policy name is within the local 17-character limit and the file is under /etc/firewalld/policies.
  • Zones are real and ordered. The intended ingress and egress zones exist and are the right way round.
  • A backup exists when an earlier policy file was replaced.
  • Validation came first. firewall-cmd --check-config returned success before the reload.
  • The policy is visible. The reloaded policy and its ports show up through firewall-cmd, or you applied the documented rollback.