Firewalld Annoyances

Latest response

What's the best way to get an EL7-based system to operate in an implicit-deny stance?

Under EL6, you'd just set the INPUT chain policy to "DROP", add just the exceptions you needed for things like SSH (and ESTABLISHED/RELATED to ensure that yum worked) and you were good to go. It seems like firewalld doesn't really offer a posture that doesn't at least send and ICMP-host-prohibited response to people probling your systems. Switching the default zone to the "drop" zone is more functionally-limiting than even just the EL6 method.

Personally, I'd rip firewalld out and just run naked iptables, but our IA team informs us that we have to run firewalld because that's the approved host-based firewall solution for RHEL7.

Ideas for how best to get back my RHEL6 behavior under firewalld? Right now, I'm about ready to murder my IA guys for focing me to have to screw with firewalld when I've got nine million things I'd rather be working on.

Responses

How about using firewalld's direct rules? These are iptables-syntax rules which are processed first in the INPUT chain:

# iptables -nL
Chain INPUT (policy ACCEPT)
target              prot opt source               destination
ACCEPT              all  --  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
ACCEPT              all  --  0.0.0.0/0            0.0.0.0/0
INPUT_direct        all  --  0.0.0.0/0            0.0.0.0/0
...
DROP                all  --  0.0.0.0/0            0.0.0.0/0            ctstate INVALID
REJECT              all  --  0.0.0.0/0            0.0.0.0/0            reject-with icmp-host-prohibited

(if you weren't already aware, firewalld is just a fancy state machine to iptables configuration)

You could then put all your ALLOW rules in the direct rules, add an explicit DROP at the end of the direct rules, and no traffic would never get processed beyond the INPUT_direct chain.

See "Direct Options" in man firewall-cmd for full syntax.

I guess it's mostly a case of, with naked iptables, you could make a really nice, compact configuration. With RHEL 6 (or RHEL7 with firewalld stripped out), you could have a really simple, compact implicit-deny configuration like:

:INPUT DROP [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT  [0:0]
-A INPUT -m state --state RELATED,ESTABLISHED -m comment --comment "Allow related and established connections" -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -d 127.0.0.0/8 ! -i lo -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
COMMIT

Even using direct rules, you've still got a page full of nonsense to wade through to try to trace out "what do I actually have in place." There doesn't seem to be a good way to get to an implicit-deny configuration that's both simple and compact to read. It's not a fatal problem but it's EXTREMELY annoying.

I'd jettison firewalld for naked iptables, but our IA guys want us to use firewalld ...because "STIGs". Then again, they also complain that their scanners don't work if we turn off ICMP responses.

Yes, I understand.

Writing rules is easy:

# firewall-cmd --direct --add-rule ipv4 filter INPUT_direct 10 -p tcp -m tcp --dport 22 -j ACCEPT
success
# firewall-cmd --direct --add-rule ipv4 filter INPUT_direct 20 -j DROP
success

Nice options to see rules in a compact format:

# firewall-cmd --direct --get-all-rules
ipv4 filter INPUT_direct 10 -p tcp -m tcp --dport 22 -j ACCEPT
ipv4 filter INPUT_direct 20 -j DROP

or:

# firewall-cmd --direct --get-rules ipv4 filter INPUT_direct
10 -p tcp -m tcp --dport 22 -j ACCEPT
20 -j DROP

These are starting to make the old way look pretty ugly:

# iptables -S INPUT
-P INPUT ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -j INPUT_direct
-A INPUT -j INPUT_ZONES_SOURCE
-A INPUT -j INPUT_ZONES
-A INPUT -m conntrack --ctstate INVALID -j DROP
-A INPUT -j REJECT --reject-with icmp-host-prohibited

# iptables -S INPUT_direct
-N INPUT_direct
-A INPUT_direct -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT_direct -j DROP

If you want ICMP returns, then don't use the explicit -j DROP. As you can see, firewalld's INPUT chain already has an explicit -j REJECT --reject-with icmp-host-prohibited at the end.

The inverse of your loopback rule already exists matching on lo, and that scales to interface names beyond eth0 so I didn't add that one.

Does that all do what you want?

Sorry. Seems like I'm failing to clearly-communicate something here. Not sure how to fix that failure on my end.

It's also a bit of frustrating that, since our IA guys are only reading documents that say "use firewalld" rather than "achieve this effective end-state", it feels like I'm stuck with a technology that seems to pointlessly gets in the way.

Direct rules are "ok", but they're only quasi-direct: I'm not actually modifying the core chains' behaviors (e.g., I'm not directly manipulating the INPUT chain, I'm manipulating the INPUT_direct chain). If I want to do something more-directly analagous to setting a default-DROP policy on the chain, I have to use the --passthrough option. Unfortunately, use of the --passthrough rules butts me up against this bit of solution-immaturity (from the firewalld reference web-site):

Permanent Direct Rules
This feature is in early state. It provides the ability to permanently save direct rules and chains. Passthorough rules are not part of this. See Direct options for more information on direct rules.

Overall, it feels like a "can't get there from here" ...particularly where "here" is equal to simple and not indirect. :-\

I think I understand, though I don't really see much difference between adding direct rules into INPUT or INPUT_direct. Sure the name is different but the end result ends up being the same. Why does it matter what the chain is called?

firewalld doesn't offer an implicit drop on a chain afaics, however it can put an explicit drop on a zone with --set-target=DROP, and you can add an explicit direct rule drop as above. Again the end result is the same, why does it matter where you do it?

I'm not actually modifying the core chains' behaviors (e.g., I'm not directly manipulating the INPUT chain, I'm manipulating the INPUT_direct chain).

Yeah, this isn't a feature of firewalld. The whole idea is to act as a frontend to iptables configuration so that the old method of modify-the-rules-file-and-restart-the-service (dropping the conntrack table in the process) becomes obsolete.

But again, why is this method a requirement for you to implement firewall rules? Just add direct rules to the firewall and let them land where firewalld puts them. Much like your requirements folks are saying "use firewalld" rather than "achieve this effective end-state", are you focusing too much on "use the INPUT chain in the old iptables method" rather than "achieve this effective end-state"? :)

Likely, my frustrations come down to having developed habits from having been at this for a couple decades, at this point. There used to be noticeable performance deltas between an iptables configuration as complicated/indirect as what firewalld default-implements and what you'd get by setting up per my 01:06 post post. It's also a administrative model/method that is as portable across firewalling solutions as you can get (given how disparate everyone's filter-management methods seem to be).

It also comes down to a general hatred for technologies that get in the way of direct-manipulation. I mean, one of the differentiators between UNIX systems and their Microsoft analogues had been ability to easily do direct manipulation. It was bad enough when Sun - as they extended SMF and related toolings in Solaris 11 - started abstracting away direct control (and, as much as I otherwise liked AIX, always hated that some functions were hidden away in their administrative object-database) The overall direction of systemd-based systems is to move more to an indirect model ...which is pyschologically icky (and likely accounts for why so many long-time admins loathe it). And "add direct rules to the firewall and let them land where firewalld puts them" is an equally hive-inducing prospect (when you're a control-freak like me and most of the SAs I know). ;)

As to "the old method of modify-the-rules-file-and-restart-the-service", all I can say is, "err: wut?" You might do that if you were only accustomed to working with the config-files rather than authoring in-memory and then flushing to disk. That said, the more-usual work-flow for most people I knew - other than simply either kickstarting to or using CM-engines to distribute standardized rule-sets - was:

  1. Determine the current state of your target chain (iptables --line-numbers -L <CHAIN> )
  2. If adding rules where order wasn't important, append the rules (iptables -A <CHAIN> <RULE>)
  3. If adding order-critical rules, insert the rules(iptables -I <CHAIN> <LINE> <RULE>)
  4. Verify that things were working as expected
  5. Do a service iptables save to flush to disk (with no need for a service restart)

In other words, work with iptables in much same way you'd work with something like ipf or a firewall appliance (show running-config; <do rule-work>; test; copy run start).

Like I say, I like some of the things firewalld has to offer. I just don't like paying the "direct/absolute control" cost to get those bits (particularly since "those bits", in the deployment cases we currently typically deal with, mostly amount to window-dressing). Thus terming the "problem" an "annoyance" rather "brokenness". ;)

And, I don't completely hate firewalld - I like the fact that I can define a complext service-configuration for an application or application-stack and sort the firewall exeecptions with a simple firewall-cmd --add-service=MyService --permanent and be done with things. It's just the lack of good, direct, low-level control that gripes me.

Have seen multiple customers find the exact same issue with firewalld and I have stripped it out of my EL7 builds.

I find managing the the firewall rules (and firewall application profiles) with Puppet a good solution while still maintaining control over exactly what goes into the firewall.

Close

Welcome! Check out the Getting Started with Red Hat page for quick tours and guides for common tasks.