Adding source IP to specific zone prevents same IP from accessing services in other zones

Hi.

I’m new to Firewalld and I’ve run my head against a wall.
I’ve setup a new zone to limit SSH logins to a single IP.

ssh-limited (active)
  target: default
  icmp-block-inversion: no
  interfaces:
  sources: <ip>
  services: ssh
  ports:
  protocols:
  forward: no
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:

I’ve added the http service to the public zone:

public (active)
  target: default
  icmp-block-inversion: no
  interfaces: ens160
  sources:
  services: http
  ports:
  protocols:
  forward: yes
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:

I can’t figure out why I can’t access http from the source IP. If I remove the IP from the ssh-limited zone, I can access port 80 just fine.
An easy solution would be to add the http service to the ssh-limited zone but that just seems… wrong.

Hoping someone can point me in the right direction.

The concept of zone is two things:

  • A set of clients
  • What those clients are allowed to access

A client belongs to exactly one zone.


You seem to have two sets of clients:

  • Those that may access http
  • Those that may access http and ssh

Perhaps calling/thinking the zones with different names makes it feel less wrong:

only_web
  interfaces: ens160
  services: http

also_ssh
  interfaces: ens160
  sources: <ip>
  services: http ssh

Thanks. It just doesn’t make any sense (unless the behavior was changed since 2017).
I found this post: Understanding Firewalld in Multi-Zone Configurations | Linux Journal
Under “A Simple Single-Zoned Example”, the author basically sets up the same configuration as I did. Remove SSH from the public zone, add a new zone with SSH and adds 1.1.1.1 as source ip to the new zone, and then add HTTP for the public zone. According to the author (and my own logic), it should work just fine:

If someone attempts to ssh from somewhere else, say 2.2.2.2, there wouldn’t be a source zone, because no zones match that source. Therefore, the request would pass directly to the interface zone (public), which does not explicitly handle ssh. Since public’s target is default, the request passes to the firewalld default action, which is to reject it.

What if 1.1.1.1 attempts http access? The source zone (internal) doesn’t allow it, but the target is default, so the request passes to the interface zone (public), which grants access.

The simple solution would be to have a zone that allowed access to ssh and http but it seems redundant. If I add more zones, I basically need to add the http service to all of them.
It makes no sense to me since the default zone allows access to the http service.

Old post. It relies on zone drifting, which apparently was a “bug”.
See Allowing Zone Drifting | firewalld

Apparently even the workaround is gone in el9: Leapp Preupgrade check fails with error - "Inhibitor: Firewalld Configuration AllowZoneDrifting Is Unsupported" . - Red Hat Customer Portal