Firewalld basics

I am not a professional firewall engineer, I just use it on Linux.

With this in mind, I have learned over the last 1+ year to list all of the zones, see how the zones are configured and so on.

The problem is I really need to understand the BASIC concepts of a firewalld firewall so that I can understand why I am doing what I am doing, not just the meaning of a --switch-option and what it does.

For examples:

  • What happens if a zone is active, but there is no interface assigned? What is the worse that could happen?

  • If the sources for a zone are defined and there are also services or ports assigned to that active zone, does that mean only those sources can access those explicitly defined services and ports? That makes sense to me, but I am experiencing something else if that is truly the case.

  • How do I know when I should use which zone for whatever purpose?

I don’t really just want the answers to these questions but maybe a pointer to a great, no fantastic, reference explaining the basics of firewalld components and concepts. I want to be strong in this technology, not just aware.

Thank you.

firewalld has some really stupid defaults (like allowing dhcp, ping and cockpit on all zones) so i’d say to either ditch it and use raw nftables - which gives you a lot more control, or delete the defaults and start from scratch.

there’s also some weirdness like firewall-offline-cmd can’t do certain things from a kickstart that firewall-cmd can in a running system, and you end up having to edit /etc/sysconfig/network-scripts/ifcfg-eth0 and the like.

and don’t get me started on the backwards icmp blocking.

the definitions of public, trusted etc. zones is not ideal either, again nuke them from orbit and make your own.

2 Likes

Hi @warron.french ,

Personally, I didn’t really liked firewalld, I considered it a strange “abstraction layer” over the netfilter capabilities of the kernel. For me, iptables was the way to go; a great tutorial, very well written is Iptables Tutorial 1.2.2
I was lucky to neglect firewalld from the beginning and go directly with iptables especially when I started using ipsets to manage very large sets of subnets in iptables rules; people reported a lot of problems when trying to use ipsets from within firewalld ( Firewalld + ipset = big problems - CentOS ).
Although iptables was a great piece of software (up to/including RHEL/CentOS 7), the inherent problems generated by the need to use in parallel iptables, ip6tables, ebtables, etc… determined the evolution towards a single routing/firewalling system that is now nftables (default in RHEL/CentOS/Alma/Rocky 8.x).

My suggestion would be to drop firewalld an focus your efforts towards learning and understanding nftables. Unfortunately I can not recommend you such a good tutorial as I mentioned above for iptables because at this moment I don’t have the time required to seriously read about it (as a quick solution, I still use iptables syntax in Alma 8, although “iptables” command actually translates the rules in nftables format, but IMHO this translation is by far more reliable than the translation from firewalld syntax).

Maybe some other community member can recommend us a good nftables tutorial…

@bogdan_ro thanks for your reply. It’s ironic to me that you suggest ditching the firewalld for iptables because approximately 2 years ago I switched to firewalld based on advice over on the CentOS Forums to move forward with firewalld as it was the future of CentOS. Ugggh.

Anyway, I still feel like I need to learn more about the basic concepts behind host-based firewalls so that I can better understand how to manage them.

Respectfully, thanks for the feedback.

@sej7278 thanks for the blunt feedback. Any suggestions though on how to continue forward with understanding what a zone is and why use one (beside, I have to.).

I know a firewall does but have never managed one. This is one of those technologies that I really need to master because I do not feel like I could justifiably be called a “Sr. Linux Engineer” if I cannot master Linux technologies like this.

So frustrating…

Firewalld is indeed an abstraction layer. Likewise “zone” is a name for one approach to organizing rules.

Note that “netfilter” and “iptables” have been superceded/replaced by “nftables” (and its tool “nft”). Alma does not have “legacy” iptables.

Websearch finds many “what is zone” blogs. The irony is that they are about routing, which is forward filtering, while the firewalld in Alma before 8.5 was all about input filtering.

Lets take crude example:

IF from A and to X THEN allow
IF from A and to Y THEN allow
IF from B and to X THEN allow
deny

If we want to allow client C reach same services as A, we have to add/modify multiple rules.

Lets “simplify” conditions:

IF from A THEN {
    IF to X THEN allow
    IF to Y THEN allow
    deny
}
IF from B THEN {
    IF to X THEN allow
    deny
}
deny

Okay, that made updates yet more complex. Lets refactor:

zoneXY() {
    IF to X THEN allow
    IF to Y THEN allow
    deny
}

zoneX() {
    IF to X THEN allow
    deny
}

IF from A THEN zoneXY()
IF from B THEN zoneX()
deny

Now we can add C with one rule: IF from C THEN zoneXY()

In other words the zone-based ruleset decouples “from-conditions” from “to-conditions”.

In FirewallD a “zone” is like one of the “functions” in above example; a set fo “to-conditions”.
The “from-conditions” are the sources and interfaces that you link to a zone.
For input filtering
The firewalld 0.9 has “policy objects” for forward filtering.

A router decides whether to forward between two subnets. Rules can/should be different if those subnets “belong to” same zone, or different zones. Different “policy”.

@jlehtone thanks for this response. For me it actually confirms some of my suspicions actually.

I have to read this over a couple of more times and mull it over, but it definitely lit a lightbulb in me.

Thanks.

I’d like to take this opportunity to bring this issue to everyone’s attention.

When firewalld was first introduced, it allowed zone drifting. In other words:

zone public allows ports: 1 2 3
zone private allows ports: 4

essentially, the above should NOT allow the private zone access to ports 1, 2 ,3, but it does! This is called zone drifting!

at some point people realized the mistake and disabled zone drifting by default, but then tons of people complained that it broke their servers due to existing configurations that expected zone drifting to work, thus a new configuration option was added:

# AllowZoneDrifting
# Older versions of firewalld had undocumented behavior known as "zone
# drifting". This allowed packets to ingress multiple zones - this is a
# violation of zone based firewalls. However, some users rely on this behavior
# to have a "catch-all" zone, e.g. the default zone. You can enable this if you
# desire such behavior. It's disabled by default for security reasons.
# Note: If "yes" packets will only drift from source based zones to interface
# based zones (including the default zone). Packets never drift from interface
# based zones to other interfaces based zones (including the default zone).
# Possible values; "yes", "no". Defaults to "yes".
AllowZoneDrifting=no

For best security practices, zone drifting should be disabled and each zone should act separately from the others.

3 Likes

yes good point, first thing i do on a box running firewalld:

sed -i 's/^AllowZoneDrifting.*/AllowZoneDrifting=no/' /etc/firewalld/firewalld.conf

the whole default setup of zones is poorly thought-out, its trying to be everything to everyone.

Same here, but I prefer to use Ansible:

- name: Firewalld disable zone drifting
  lineinfile:
    path: /etc/firewalld/firewalld.conf
    regexp: "^AllowZoneDrifting="
    line: "AllowZoneDrifting=no"

:smiley:

1 Like

What is the context of ports 1, 2, 3, and 4 anyway? They are not physical ethernet ports because if they were they would be named something like ethX, ensXfY, enp… well, you get my drift.

Your explanation is eloquent, thank you, but I still do not have a context to what 1-4 is referring.

“Ports”. The TCP and UDP do have multiple ports. For example, tcp/22 is the port that SSHD does listen by default. Had the example been any clearer with more explicit ports, like:

zone public allows ports: ssh, http, https
zone private allows ports: nfs

If the explanation was missing anything, then it was that it did not reiterate that public is the default zone.

1 Like

@warron.french You are mixing up physical ports and TCP or UDP ports. Sams_daughter was referring to something along the lines of 192.168.1.2:22 for instance which is the well known port for ssh.

@jlehtone and @MartinR , so the references to ports 1, 2, 3, and 4 were merely notional not actually specific ports?

I wasn’t sure if they were physical - that’s why I had to ask for clarification. I know that TCP and UDP have their own port associations.

With zone drifting we have something similar to:

IF from A THEN zoneXY()  #1
zoneDefault()            #2
deny                     #3

Without zone drift we have something similar to:

IF from A THEN zoneXY()  #1
ELSE zoneDefault()       #2
deny                     #3

If a zone is written:

zoneXY() {
    // rules that allow specific connections
}

then drift will pass the packages that were not allowed in zoneXY() into the zoneDefault(),
but without drift we jump to the final rule: deny #3

If a zone is written:

zoneXY() {
    // rules that allow specific connections
    deny
}

then every packet that enters zoneXY() is handled (allowed or denied) by this zone. There is nothing that can drift. Alas, zones like ‘public’ do not handle all packages.

You can have even more fun with nftables. There can be multiple chains with different priorities. If I understand those correctly, denied packets are really denied on the spot but allowed packets are merely passed to lower priority chains (which could deny them).

Is there supposed to be an “OR” before zoneDefault() #2, for clarity’s sake?

No. The lack of ELSE is precisely why zone drifting is nasty.

Yep! I can totally agree with that.