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.
The route
Jump straight to the step you need, or tick off Done means at the end.
- 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 limitspolicy_nameto 17 characters, so this guide useslab-egress. - Location. Host-specific policy files belong in
/etc/firewalld/policies. Files in/usr/lib/firewalld/policiesare 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
teeneeds 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-zonesshows 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/policiesis 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.
CONTINUEis 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-cmdmay not be the file you are inspecting. - Do not swap in a terminal target casually.
ACCEPT,REJECTorDROPin place ofCONTINUEdecides 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-configreturnedsuccessbefore the reload. - The policy is visible. The reloaded policy and its ports show up through
firewall-cmd, or you applied the documented rollback.