How to replace firewalld direct rules with nftables?

Solution Verified - Updated

Environment

  • Red Hat Enterprise Linux 9.5 and later
  • firewalld firewall with direct rules

Issue

  • What is the replacement for firewall direct rules?
  • firewalld considers the direct rule syntax to be deprecated, what do I do for firewall rules which firewalld cannot support?
  • How to convert firewalld direct rules to nftables?

Resolution

Note: Design of Rule Ordering

Just like with direct rules, when there are multiple chains using the same hook (eg: the input filter hook) then all those chains are traversed until the packet reaches a drop verdict or reaches the end of the chains.

The nftables wiki page Content from wiki.nftables.org is not included.Base chain priority also explains the behavior:

If a packet is accepted and there is another chain, bearing the same hook type and with a later priority, then the packet will subsequently traverse this other chain. Hence, an accept verdict - be it by way of a rule or the default chain policy - isn't necessarily final. However, the same is not true of packets that are subjected to a drop verdict. Instead, drops take immediate effect, with no further rules or chains being evaluated.

This means that an accept verdict does NOT cause a packet to exit the firewall, but a drop verdict does.

Given a rule setup like:

  • nftables - filter priority default, default target accept
  • firewalld - filter priority + 10, default target accept, plus explicit reject at the end

Packets which reach an nftables drop will exit the firewall and be dropped. Packets which pass an nftables accept will enter firewalld rules.

Given a rule setup like:

  • firewalld - filter priority + 10, default target accept, plus explicit reject at the end
  • nftables - filter priority + 20, default target accept

Packets which pass a firewalld accept will enter nftables rules. Packets which reach the firewalld reject will exit the firewall and be dropped. Packets dropped by firewalld will never enter nftables.

Because of this, it makes most sense to:

Converting Rules

List the firewalld direct rules, eg:

# firewall-cmd --direct --get-all-rules
ipv4 filter INPUT 1 -p tcp --dport 9001 -m state --state NEW -j DROP

Observe any table and chains where rules are added.

Tables are named filter, nat, mangle, or raw.

Chains are named INPUT, OUTPUT, FORWARD, PREROUTING, or POSTROUTING.

List the direct rules using -s to get stateless output (no counter values). Direct rules will appear in chains named with capital letters:

# nft -s list ruleset

... firewalld rules omitted ...

table ip filter {
        chain INPUT {
                type filter hook input priority filter; policy accept;
                tcp dport 9001 ct state new counter drop
        }
}

Any table/chain where direct rules were defined, copy that table/chain to a file, and save it in the nftables configuration location /etc/sysconfig/nftables.conf.

Ensure this rules file has flags persist in the table:

/etc/sysconfig/nftables.conf

flush ruleset

table ip filter {
    flags persist;
    chain INPUT {
        type filter hook input priority filter; policy accept;
        tcp dport 9001 ct state new counter drop;
    }
}

Delete old Direct Rules from firewalld

Once direct rules have been moved from firewalld to nftables, remove the old rule from firewalld:

# firewall-cmd --direct --remove-rule ipv4 filter INPUT 1 -p tcp --dport 9001 -m state --state NEW -j DROP
# firewall-cmd --runtime-to-permanent

Start the nftables systemd service

Both firewalld and nftables services can now be started together, and they will not override the other's rules:

# systemctl enable --now nftables.service

Verify Rules

# nft -s list ruleset

table inet firewalld { # progname firewalld
        flags owner,persist

        ... firewalld rules omitted ...
}

table ip filter {
        flags persist

        chain INPUT {
                type filter hook input priority filter; policy accept;
                tcp dport 9001 ct state new counter drop
        }
}

Root Cause

firewalld direct rules use the old iptables interface to the kernel's netfilter firewall. iptables is deprecated and will eventually be removed from the Linux Kernel and from RHEL.

The supported interface to add rules to the firewall is nftables. firewalld is an easy user interface to nftables.

Due to the hook-based nature of nftables, it is possible to run both the firewalld and the nftables service together where each service applies its own firewall rules. This is one advantage that nftables has over iptables - many different participants (firewalld, podman, libvirt, etc) could add their own firewall rules without affecting the other participants.

To work with rules in the nftables firewall, some knowledge of nftables command and rule syntax is required. Red Hat and community references are available at:

RHEL 9.5 adds the owner and persist flags to nftables which allows both firewalld and nftables services to each add their own firewall rules without disturbing the other service's rules.

Components

This solution is part of Red Hat’s fast-track publication program, providing a huge library of solutions that Red Hat engineers have created while supporting our customers. To give you the knowledge you need the instant it becomes available, these articles may be presented in a raw and unedited form.