A few ways to configure Linux firewalld
The method for configuring Linux servers' firewalls changed with RHEL 7 and other new distributions. Learn how to set up firewalld, and what to avoid.
Initially, firewalld looks difficult to use, but it really isn't. Services and zones make it easy to put the pieces together and configure Linux firewalls.
Although it also works on the netfilter code in the Linux kernel, firewalld is totally incompatible with the old way to configure Linux firewalls. Red Hat Enterprise Linux 7 and other current distributions rely on this new method.
All examples of commands in this article are based on RHEL 7.
Firewalld works with zones
First, verify that firewalld is running. Use the command systemctl status firewalld
(Listing 1).
Listing 1. This sequence shows that firewalld is active and running. Some lines were ellipsized; use -l
when you try it to show them in full.
[root@rhelserver ~]# systemctl status firewalld
firewalld.service - firewalld - dynamic firewall daemon
Loaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled)
Active: active (running) since Thu 2014-05-22 07:48:08 EDT; 14min ago
Main PID: 867 (firewalld)
CGroup: /system.slice/firewalld.service
└─867 /usr/bin/python -Es /usr/sbin/firewalld --nofork --nopid
May 22 07:48:08 rhelserver.example.com systemd[1]: Started firewalld - dynami...
Everything in firewalld relates to one or more zones.
After installation, a RHEL 7 server is normally in the public zone, but you may want to add it to another zone to easily configure firewall access. The command firewall-cmd --get-default-zone
shows which zone you're in, and firewall-cmd --get-zones
shows the available zones. For detailed information about the configuration of a specific zone, you can use firewall-cmd --zone=zonename --list-all
(Listing 2).
Listing 2. These commands show the zone or zones in which you're setting up Linux firewalls.
root@rhelserver ~]# firewall-cmd --get-default-zone
public
[root@rhelserver ~]# firewall-cmd --get-zones
block dmz drop external home internal public trusted work
[root@rhelserver ~]# firewall-cmd --zone=public --list-all
public (default, active)
interfaces: ens33
sources:
services: dhcpv6-client sander ssh
ports:
masquerade: no
forward-ports:
icmp-blocks:
rich rules:
Changing the current zone isn't difficult: Use firewall-cmd --set-default-zone=home
, for example, to change the default zone assignment from public to home.
Services and other building blocks
There are a few basic building blocks in the zones -- services are the most important. Firewalld uses its own set of services that are configured using XML files in the directories /usr/lib/firewalld/services (for the system default services) and /etc/firewalld/services for services that you, the administrator, create. To configure services, create an XML file based on the example from Listing 3.
Listing 3. An example of a configuration of firewalld services.
[root@rhelserver services]# cat ftp.xml
<?xml version="1.0" encoding="utf-8"?>
<service>
<short>FTP</short>
<description>FTP is a protocol used for remote file transfer. If you plan to make your FTP server publicly available, enable this option. You need the vsftpd package installed for this option to be useful.</description>
<port protocol="tcp" port="21"/>
<module name="nf_conntrack_ftp"/>
</service>
Each service definition needs a short name, a description, a port section that specifies the protocol and port to be used, and a module name.
Listing 4. This example of a configuration file will create a firewalld service.
[root@rhelserver services]# cat sander.xml
<?xml version="1.0" encoding="utf-8"?>
<service>
<short>Sander</short>
<description>Sander is a random service to show how service configuration works.</description>
<port port="666" protocol="tcp"/>
</service>
Once you have the right service file, use these commands to manipulate it.
The command firewall-cmd --list-services
shows a list of all services that were found on your server. To add a service, use firewall-cmd --add-service yourservice
to put it into the default zone, or add --zone=zonename
to choose a specific zone.
Here's how it works:
1. The command firewall-cmd --zone=public --list-all
shows the current configuration of the public zone.
[root@rhelserver ~]# firewall-cmd --zone=public --list-all
public (default, active)
interfaces: ens33
sources:
services: dhcpv6-client ssh
ports:
masquerade: no
forward-ports:
icmp-blocks:
rich rules:
2. The command firewall-cmd --zone=public --add-service=ftp
adds the FTP service to the public zone in the Linux firewall.
3. Verify that the FTP service was added successfully by repeating step 1. You will see it in the list of services.
4. Restart your server and repeat step 1. You will see that the FTP service has disappeared. In firewalld, nothing is permanent unless you use the option --permanent.
5. To add FTP to the public zone and make it a permanent setting, use firewall-cmd --permanent --zone=public --add-service=ftp.
It will now survive a reboot.
6. Type firewall-cmd --reload
to apply all rules and reload the firewall.
It is extremely important when working with firewalld to use the --permanent
option to make settings permanent.
Breaking the rules
Services are the preferred way of configuring firewalld, easily providing a global overview of what your firewall is doing. But if you don't want to make your own service file in /etc/firewalld/service, you can add ports without them.
To assign a specific port to a specific zone, use a command like firewall-cmd --permanent --zone=dmz --add-port=22/tcp
, then use firewall-cmd --zone=dmz --list-all
to verify that the port was added successfully. While this is an uncomplicated way to add a port, going through services makes it easier to distribute similar rules across different hosts. Without services, files are hard to distribute, and rules in a configuration file are not that easy.
For even more control, you can -- but shouldn't -- use a direct rule. Here's why:
1. Type firewall-cmd --direct --add-rule ipv4 filter INPUT 0 -p tcp --dport 80 -j ACCEPT.
2. Now type firewall-cdm --list-all
to show the configuration for your default zone. Nothing was added that relates to port 80.
[root@rhelserver ~]# firewall-cmd --list-all
public (default, active)
interfaces: ens33
sources:
services: dhcpv6-client ftp ssh
ports:
masquerade: no
forward-ports:
icmp-blocks:
rich rules:
Nothing appears about the HTTP port you added because direct rules are writing to the iptables interface, not to firewalld.
3. To show direct rules, use firewall-cmd --direct --get-all-rules
. Or use the deprecated command iptables -L
instead.
Instead of direct rules, use rich rules, which are written to firewalld instead of iptables
(Listing 5).
Listing 5. An example of a rich rule in Linux firewalld.
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.4.0/24" service name="tftp" log prefix="tftp" level="info" limit value="1/m" accept"
Firewalld rich rules offer a maximum amount of flexibility that is similar to what is possible on an iptables firewall.
Many things are accomplished and applied all in Listing 5's one rule. The specification of IP family, source address and services name may be obvious, but note how the rule handles logging: A specific log prefix is defined, as well as a log level info and a limit value of one message per minute. max.
The Linux administrator can apply filters that look at more than just ports, so rich rules are particularly useful to filter on IP addresses (Listing 6).
Listing 6. This rich rule applies a filter on IP addresses for the Linux firewall.
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" \
source address="192.168.0.4/24" service name="http" accept"
Analyzing zones
The firewall-cmd
command is one of many methods to configure firewalld. Alternatively, you can edit the zone configuration file directly. This doesn't give you any feedback on wrong syntax, but it's a clean and straightforward configuration file that is easy to modify and distribute across multiple servers.
Listing 7. You can configure firewalld by editing the zone configuration file.
<?xml version="1.0" encoding="utf-8"?>
<zone>
<short>Public</short>
<description>For use in public areas. You do not trust the other computers on networks to not harm your computer. Only selected incoming connections are accepted.</description>
<service name="dhcpv6-client"/>
<service name="ssh"/>
<rule family="ipv4">
<source address="192.168.4.0/24"/>
<service name="tftp"/>
<log prefix="tftp" level="info">
<limit value="1/m"/>
</log>
<accept/>
</rule>
</zone>
The example in Listing 7 includes all that was added in the previous examples, written directly to the zone configuration file, with the exception of direct rules. Direct rules have their own configuration file:
[root@rhelserver firewalld]# cat direct.xml
<?xml version="1.0" encoding="utf-8"?>
<direct>
<rule priority="0" table="filter" ipv="ipv4" chain="INPUT">-p tcp --dport 80 -j ACCEPT</rule>
</direct>