Policy Objects: Introduction

A new feature, policy objects, will be part of the next firewalld feature release (v0.9.0). This is a major feature that has been in the works for almost a full year. It is significant because it closes one of the long standing gaps in firewalld’s functionality: forward and output filtering.

Motivation

With some exceptions (e.g. masquerade, forward-ports) firewalld was previously limited to being an end-station firewall. This meant you could not use it to filter traffic flowing between virtual machines, containers, and zones. A subset of that functionality was available by using the direct interface and writing your own iptables rules, but it wasn’t a great user experience.

What is needed is a way to apply a policy for traffic flowing between zones. Then the user can attach firewalld’s primitives: services, ports, rich rules, etc. to the policy. The end result is something that provides a very similar user interface to zones, but is much more powerful.

What does it look like?

Manipulating policies is very similar to zones. This was a deliberate design decision to make them approachable for existing firewalld users.

Here are some examples for adding features to a policy:

# firewall-cmd --policy mypolicy --add-service ssh
# firewall-cmd --policy mypolicy --add-port 1234/tcp
# firewall-cmd --policy mypolicy --add-masquerade

This example shows the settings of the built-in policy allow-host-ipv6.

# firewall-cmd --info-policy allow-host-ipv6
allow-host-ipv6 (active)
  priority: -15000
  target: CONTINUE
  ingress-zones: ANY
  egress-zones: HOST
  services:
  ports:
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:
       rule family="ipv6" icmp-type name="neighbour-advertisement" accept
       rule family="ipv6" icmp-type name="neighbour-solicitation" accept
       rule family="ipv6" icmp-type name="router-advertisement" accept
       rule family="ipv6" icmp-type name="redirect" accept

Relationship to Zones

Policies are applied to traffic flowing between zones in a stateful unidirectional manner. This allows different policies depending on the direction of traffic.

+----------+     policyA     +----------+
|          |  <------------  |          |
| libvirt  |                 |  public  |
|          |  ------------>  |          |
+----------+     policyB     +----------+

This diagram shows policyA that applies to traffic flowing from the public zone to the libvirt zone. policyB applies to traffic flowing from the internal zone to the public zone.

The configuration changes necessary to result in the diagram above are:

# firewall-cmd --permanent --new-policy policyA
# firewall-cmd --permanent --policy policyA --add-ingress-zone public
# firewall-cmd --permanent --policy policyA --add-egress-zone libvirt

# firewall-cmd --permanent --new-policy policyB
# firewall-cmd --permanent --policy policyB --add-ingress-zone libvirt
# firewall-cmd --permanent --policy policyB --add-egress-zone public

Manipulating Policies

Policies must be created by the user.

# firewall-cmd --permanent --new-policy mypolicy

Ingress and Egress Zones

As shown in the diagram above policies exists between zones. This means a set of ingress and egress zones must be defined before the policy becomes active. In this context an ingress zone is the zone from which the packet originated. The egress zone is the zone to which the packet is destined.

This example makes mypolicy apply to traffic flowing from the public zone to the internal zone:

# firewall-cmd --permanent --policy mypolicy --add-ingress-zone public
# firewall-cmd --permanent --policy mypolicy --add-egress-zone internal

The ingress and egress zone list can also be manipulated in the runtime configuration. It is also valid to use multiple zones in the ingress and egress zone lists.

# firewall-cmd --policy mypolicy --add-ingress-zone public
# firewall-cmd --policy mypolicy --add-ingress-zone external

Making a policy go inactive is done by emptying the ingress and/or the egress zone list.

# firewall-cmd --policy mypolicy --remove-ingress-zone internal

Priority

Multiple policies can be applied to the same set of traffic. Therefore it’s useful to have a priority to sort the policies by precedence.

# firewall-cmd --permanent --policy mypolicy --set-priority -500

The following rules apply to policy priorities:

  1. policies with negative priorities apply before rules in zones
  2. policies with positive priorities apply after rules in zones
    • This is especially important to understand because many zones have catch all accept/drop/reject. This applies to zone with a --set-target that is not default.
  3. priority 0 is reserved and not usable

Default Target

Policies have a --set-target option just like zones. This is a catch-all at the end of the policy’s rules. The default is CONTINUE which means packets will be subject to rules in following policies and zones. Other values are: ACCEPT, DROP, and REJECT.

# firewall-cmd --permanent --policy mypolicy --set-target CONTINUE

Symbolic Zones

There are a couple of symbolic zones for use in the ingress and egress zone lists: HOST, and ANY. HOST is used to allow policies for traffic originating from or destined to the host running firewalld. ANY is used to apply a policy to all current and future zones. ANY is effectively a wildcard for all zones.

This example, creates a policy that applies to traffic originating from the host running firewalld and is destined to any zone. Or said differently traffic in the OUTPUT chain.

# firewall-cmd --permanent --new-policy myOutputPolicy
# firewall-cmd --permanent --policy myOutputPolicy --add-ingress-zone HOST
# firewall-cmd --permanent --policy myOutputPolicy --add-egress-zone ANY

Man Pages

There are new man pages for policies.

Default Policies

At present firewalld ships with a single built-in policy: allow-host-ipv6. This policy is active by default and allows a subset of ICMPv6 necessary for bootstrapping IPv6 connectivity.


firewalld 0.7.5 release

A new release of firewalld, version 0.7.5, is available.

This is a bug fix only release.

Alexander Bokovoy (1):

  • fix: update dynamic DCE RPC ports in freeipa-trust service

Eric Garver (30):

  • fix(systemd): Conflict with nftables.service
  • fix(direct): rule in a zone chain
  • test(direct): rule in a zone chain
  • fix(client): addService needs to reduce tuple size
  • test(dbus): zone: fix false failure due to list order
  • test(dbus): zone: fix zone runtime functional test title
  • fix(doc): dbus: signatures for zone tuple based APIs
  • fix(config): bool values in dict based import/export
  • fix(dbus): service: don’t cleanup config for old set APIs
  • fix(ipset): flush the set if IndividiualCalls=yes
  • fix(firewall-offline-cmd): remove instances of “[P]” in help text
  • docs: replace occurrences of the term blacklist with denylist

Phil Sutter (1):

  • fix: core: rich: Catch ValueError on non-numeric priority values

Vrinda Punj (3):

  • docs(README): add libxslt for doc generation
  • fix(cli): add –zone is an invalid option with –direct
  • fix(cli): add ipset type hash:mac is incompatible with the family parameter

Source available here:


firewalld 0.8.3 release

A new release of firewalld, version 0.8.3, is available.

This is a bug fix only release.

Alexander Bokovoy (1):

  • fix: update dynamic DCE RPC ports in freeipa-trust service

Eric Garver (33):

  • fix: nftables: ipset: port ranges for non-default protocols
  • fix(systemd): Conflict with nftables.service
  • fix(direct): rule in a zone chain
  • fix(client): addService needs to reduce tuple size
  • fix(doc): dbus: signatures for zone tuple based APIs
  • fix(config): bool values in dict based import/export
  • fix(dbus): service: don’t cleanup config for old set APIs
  • fix(ipset): flush the set if IndividiualCalls=yes
  • fix(firewall-offline-cmd): remove instances of “[P]” in help text
  • fix(rich): source mac with nftables backend
  • docs: replace occurrences of the term blacklist with denylist

Phil Sutter (1):

  • fix: core: rich: Catch ValueError on non-numeric priority values

Vrinda Punj (3):

  • docs(README): add libxslt for doc generation
  • fix(cli): add –zone is an invalid option with –direct
  • fix(cli): add ipset type hash:mac is incompatible with the family parameter

Source available here:


Intra Zone Forwarding

A new feature, intra zone forwarding, is coming to firewalld. This feature allows packets to freely forward between interfaces or sources with in a zone.

Why is it needed?

One axiom of zone based firewalls is that traffic with in a zone can flow from interface (or source) to interface (or source). The zone specifies the trust level of all those interfaces and sources. If they have the same trust level then they can communicate unencumbered. Firewalld has lacked this functionality until now.

What does it look like?

This feature does not bring many CLI additions; only a couple knobs to enable or disable it for the zone.

Let’s say we have our home zone with two interfaces: dummy1, and dummy2

# firewall-cmd --zone=home --add-interface=dummy1 --add-interface=dummy2

Now let’s enable intra zone forwarding.

# firewall-cmd --zone=home --add-forward

This results in the following nftables rules being added to the zone.

table inet firewalld {
    chain filter_FWDI_home_allow {
        oifname "dummy1" accept
        oifname "dummy2" accept
    }
}

The rules say: if the packet is destined to the any interface in the zone home then go ahead and accept it.

If we were to add another interface or source to the home zone then we will see it show up in the ruleset as well.

# firewall-cmd --zone=home --add-source 10.10.10.0/24

And the result:

table inet firewalld {
    chain filter_FWDI_home_allow {
        oifname "dummy1" accept
        oifname "dummy2" accept
        ip daddr 10.10.10.0/24 accept
    }
}

Doesn’t this already happen?

Some zones use a --set-target of ACCEPT. Those zones immediately accept all forwarded traffic. As such, the new --add-forward option has no effect for them.

For all others --set-target values forwarded traffic is dropped by default. This includes all stock zones except trusted.

Caveats

When enabled in the default zone, intra zone forwarding can only be applied to the interfaces and sources that have been explicitly added to the current default zone. It can not use a catch-all for all outgoing interfaces as this would allow packets to forward to an interface or source assigned to a different zone.

Default value

By default, all currently shipped zone definitions and user created zones have forward disabled. This is done as to not introduce any surprising behavioral changes.

In the future this may change. It may make sense to enable by default in at least these zones: internal, home, and work.

Contributed By

This feature was initially contributed by github user @danc86 in pull request #586.


firewalld 0.7.4 release

A new release of firewalld, version 0.7.4, is available.

This is a bug fix only release.

However, it does reintroduce the zone drifting bug as a feature. This behavior is disabled by default.

  • improvement: build: add an option to disable building documentation
  • Typo in firewall-config(1)
  • Fix typo in TFTP service description
  • doc: README: add note about language translations
  • fix: rich: source/dest only matching with mark action
  • feat: AllowZoneDrifting config option
  • feat: nftables: support AllowZoneDrifting=yes
  • feat: ipXtables: support AllowZoneDrifting=yes
  • test: verify AllowZoneDrifting=yes
  • fix: firewall-offline-cmd: Don’t print warning about AllowZoneDrifting
  • fix: add logrotate policy
  • fix: tests: regenerate testsuite if …/{cli,python}/*.at changes
  • doc: direct: add CAVEATS section
  • fix: checkIP6: strip leading/trailing square brackets
  • fix: nftables: remove square brackets from IPv6 addresses
  • fix: ipXtables: remove square brackets from IPv6 addresses
  • fix: nftables: zone dispatch with multidimensional ipsets
  • fix: ipset: destroy runtime sets on reload/stop
  • fix: port: support querying sub ranges
  • fix: source_port: support querying sub ranges
  • doc: specify accepted characters for object names
  • fix: doc: address copy/paste mistakes in short/description
  • fix: configure: atlocal: quote variable values
  • fix: nftables: allow set intervals with concatenations
  • doc: clarify –set-target values “default” vs “reject”

Source available here: