Rich rules are an additional feature of firewalld that allows you create more sophisticated firewall rules. For example:
Announcement
You can find all my latest posts on medium.- whitelist an ip range with the exception of one ip that’s in this range.
- reroute incoming request from one port, and forward it to another port. For example, you might want people to ssh into a box using port 4234 instead of the standard port 22, for improved security. then get firewalld to reroute this traffic to sshd daemon which is listening on port 22. In this scenario, there would be no actual services listening on port 4234, but firewalld will intercept them and forward it onto port 22.
- limit how many incoming requests comes in per second/minute/hour/day.
- write particular log entries into /var/log/messages when certain requests come through
You can follow along with this article by using our vagrant environment on github. this environment is made up of 2 CentOS boxes, ‘client’ and ‘webserver’.
+-------------------+ +-----------------+ | | | | | Client | | Webserver | | (10.0.50.10) | Port 80 | (10.0.50.11) | | +----------->| | | | | | | | | | | | | | | | | | | | | | +-------------------+ +-----------------+
The syntax for creating rich rules is quite complicated, but luckily there’s a man page to help you in case you forget:
$ man firewalld.richlanguage
Furthermore, it’s actually a lot easier to create rich rules using the firewall gui tool:
$ firewall-config
Here’s an example of adding a rich rule via the command line:
$ firewall-cmd --permanent --zone=public --add-rich-rule='rule family=ipv4 source address=10.0.50.10/32 service name=http log level=notice prefix="firewalld rich rule INFO: " limit value="100/h" accept' success
Here we are creating a rich rule that needs to be applied to ipv4. This rule applies when the source address is 10.0.50.10 and is seeking to access the http service. When these criteria are met notice-level log entry are made to /var/log/messages, and also this rule will limit access to 100 request per hour from this source IP. This in turn looks like this:
[root@client ~]# firewall-cmd --zone=public --list-all public (active) target: default icmp-block-inversion: no interfaces: enp0s3 enp0s8 sources: services: ssh dhcpv6-client ports: protocols: masquerade: no forward-ports: source-ports: icmp-blocks: rich rules: rule family="ipv4" source address="10.0.50.10" service name="http" log prefix="firewalld rich rule INFO: " level="notice" limit value="100/h" accept
Port forwarding using rich rules
Now let’s say we want to improve security of webserver by setting it up so that client can only ssh to webserver using port ‘42343’. At the moment this won’t work:
$ [root@client ~]# ssh -p 42343 vagrant@webserver ssh: connect to host 10.0.50.10 port 42343: No route to host
That’s because by default the sshd daemon on webserver listens on port 22 (if we omitted the ‘-p 42343’ bit then it would have worked). However with firewalld we can fix this issue, by configuring firewalld to:
- forward traffic from port 42343 to port 22
- block all traffic directly going to port 22
First we ensure firewalld daemon is running:
[root@webserver ~]# firewall-cmd --state running
Next we check which zones are currently active (i.e. have an interfaces/sources assigned to them):
[root@webserver ~]# firewall-cmd --get-active-zones public interfaces: enp0s3 enp0s8 enp0s9
Only the ‘public’ zone is active, so let’s get more details about this zone:
[root@webserver ~]# firewall-cmd --zone=public --list-all public (active) target: default icmp-block-inversion: no interfaces: enp0s3 enp0s8 enp0s9 sources: services: ssh dhcpv6-client ports: protocols: masquerade: no forward-ports: source-ports: icmp-blocks: rich rules:
As you can, this zone whitelisted ssh traffic, as long as it’s for port 22. Now we want firewalld to forward traffic from port 42343 to 22, which we can set like this:
$ firewall-cmd --zone=public --add-rich-rule='rule family=ipv4 source address=10.0.50.10 forward-port port=42343 protocol=tcp to-port=22'
This in turn results in the rich rule section becoming populated:
[root@webserver ~]# firewall-cmd --zone=public --list-all public (active) target: default icmp-block-inversion: no interfaces: enp0s3 enp0s8 enp0s9 sources: services: ssh dhcpv6-client ports: protocols: masquerade: no forward-ports: source-ports: icmp-blocks: rich rules: rule family="ipv4" source address="10.0.50.10" forward-port port="42343" protocol="tcp" to-port="22"
Now if we log into the client, if we try logging in again:
[root@client ~]# ssh -p 42343 vagrant@10.0.50.10 vagrant@10.0.50.10's password: (in our case, the password is 'vagrant') Last login: Thu Feb 22 12:52:37 2018 from 10.0.50.10 [vagrant@webserver ~]$
Success! It worked. However at this stage client can still ssh in using the default port 22. So to block that off we do:
[root@webserver ~]# firewall-cmd --remove-service=ssh --zone=public success
So the end result looks like this:
[root@webserver ~]# firewall-cmd --zone=public --list-all public (active) target: default icmp-block-inversion: no interfaces: enp0s3 enp0s8 enp0s9 sources: services: dhcpv6-client ports: protocols: masquerade: no forward-ports: source-ports: icmp-blocks: rich rules: rule family="ipv4" source address="10.0.50.10" forward-port port="42343" protocol="tcp" to-port="22"
This now has the desired result:
[root@client ~]# ssh vagrant@10.0.50.10 ssh: connect to host 10.0.50.10 port 22: No route to host [root@client ~]# ssh -p 42343 vagrant@10.0.50.11 vagrant@10.0.50.10's password: Last login: Thu Feb 22 12:55:11 2018 from 10.0.50.10 [vagrant@webserver ~]$
Note that ssh daemon on webserver is still listening on port 22, and there is no daemon actually listening on port 42343. However firewalld is monitoring the destination ports of all traffic and reroutes all port 42343 destined data packets and re-routes (aka port-forwards) them.
Once you are happy with the firewall setting, then make them persistant by running:
[root@webserver ~]# firewall-cmd --runtime-to-permanent success
Real world scenario
In the above example, we restricted ssh access to webserver to only client (10.0.50.10). However in the real world it’s more likely that you want to whitelist an ip range:
[root@webserver ~]# firewall-cmd --zone=public --add-rich-rule='rule family=ipv4 source address=10.0.50.10/24 forward-port port=42343 protocol=tcp to-port=22' success
…or just do port forwarding without any ip restrictions:
[root@webserver ~]# firewall-cmd --zone=public --add-rich-rule='rule family=ipv4 forward-port port=42343 protocol=tcp to-port=22' success
Another option is to not use firewalld at all, instead just reconfigure the service in question to listen on a different port number.
Recommended Videos
https://app.pluralsight.com/library/courses/security-network-host-lfce/table-of-contents
[post-content post_name=rhsca-quiz]
- whitelist an ip range with the exception of one ip that’s in that range.
- reroute incoming request from one port, and forward it to another port.
- limit how many incoming requests comes in per second/minute/hour/day.
- write particular log entries into /var/log/messages when certain requests come through
$ man firewalld.richlanguage
using the GNOME desktop gui
$ firewall-config
– rule (accepts ‘family’ setting)
– source (accepts ‘address’ setting)
– service (accepts ‘name’ setting)
– log (accepts ‘level’ and ‘prefix’ settings)
– limit (accepts ‘value’ setting)
$ firewall-cmd –permenent –add-rich-rule='{insert-rich-rule-here}’
$ firewall-cmd –permanent –zone=public –add-rich-rule=’rule family=ipv4 source address=10.0.50.10/32 service name=http log level=notice prefix=”firewalld rich rule INFO: ” limit value=”100/h” accept’
success
$ systemctl restart firewalld
# note, this will give the source access, even if http isn’t added as a service itself.
$ firewall-cmd –add-rich-rule=’rule family=ipv4 source address=10.0.50.10/24 forward-port port=12345 protocol=tcp to-port=22′
$ firewall-cmd –runtime-to-permanent
answer
answer
answer
answer