In CentOS 7 the FirewallD has appeared to configure traffic filtering rules. It is the tool recommended to be used to manage iptables rules. CentOS 8 is using nftables framework instead of the standard iptables packet filtering service, and when you configure firewall rules in firewalld, you are actually configure nftables. In this article we’ll consider how to install and configure firewalld on a server running Linux CentOS 8 (and CentOS 7) and the main concepts of this firewall.
Firewalld Basic Concepts: Zones & Rules
Prior to the installation and configuration of firewalld, we’ll learn what zones are used to determine the level of trust to different connections. You can apply different filtering rules to firewalld zones, set active firewall options for predefined services, protocols or ports, port forwarding and rich-rules.
Firewalld is filtering the inbound traffic by zones depending on the rules applied to a zone. If a sender IP address matches the rules of a zone, the packet will be sent through this zone. If the IP address does not match either of the zones configured on the server, the default zone will process the packet. When you install firewalld, the default zone is called public.
Firewalld has some zones with preconfigured permissions for different services. You can use these settings or create your own zones. Here is the list of default zones created when you install firewalld (located in /usr/lib/firewalld/zones/):
drop | It has the minimum trust level. All inbound connections are blocked with no response, only outbound connections are allowed. |
block | This zone is similar to the previous one, but incoming requests are rejected with an icmp-host-prohibited message for IPv4 or an icmp6-adm-prohibited message for IPv6. |
public | It is used for public, untrusted networks. You can allow incoming connections individually. |
external | It refers to any external network when your firewall is used as a gateway. It is used to masking NAT, so your internal network stays private, but available. |
internal | It is the antonym of the external zone. The host has a sufficient trust level, a number of additional services are accessible. |
dmz | This zone is used for computers in the demilitarized zone (DMZ) and includes isolated computers with no access to your network. Only selected incoming connections are allowed. |
work | It is a zone for your work computers (most computers in the network are trusted) |
home | It refers to a home network. You can trust most of other computers, but only selected incoming connections are supported. |
trusted | All computers in the network are trusted. It is the most open option that requires responsible use. |
Firewalld uses two sets of rules — permanent and runtime. Runtime rules are active till a server restart. By default, the rules you add to firewalld are considered runtime. To add a permanent rule, you have to use the –permanent flag. These rules will be applied after the server restart.
How to Install & Enable FirewallD in CentOS?
In CentOS 7/8 firewalld is installed by default during the OS installation. If you have removed firewalld and want to install it back, you can use the standard yum/dnf package manager:
# yum install firewalld -y
— on Centos 7
# dnf install firewalld -y
— on Centos 8
In order the firewalld daemon to start automatically add it to startup:
# systemctl enable firewalld
And start it:
# systemctl start firewalld
Check the service status:
# systemctl status firewalld
● firewalld.service - firewalld - dynamic firewall daemon Loaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled; vendor preset: enabled) Active: active (running) Docs: man:firewalld(1) Main PID: 13646 (firewalld) CGroup: /system.slice/firewalld.service └─13646 /usr/bin/python2 -Es /usr/sbin/firewalld --nofork --nopid systemd[1]: Starting firewalld - dynamic firewall daemon...
Or do it using this command:
# firewall-cmd --state
# firewall-cmd --state
running
Managing FirewallD Rules
Default FirewallD Rules
Before configuring firewalld rules, you should check, which zone is used by default:
# firewall-cmd --get-default-zone
Since we have just installed firewalld and have not configured it yet, the default zone is public.
Check the active zone. There is only one and the same zone — public:
# firewall-cmd --get-active-zones
public interfaces: eth0
As we can see, eth0 interface is managed by the public zone.
# ip link show
or:
# nmcli device status
To view the rules of the active zones, use thecommand:
# firewall-cmd --list-all
public (active) target: default icmp-block-inversion: no interfaces: eth0 sources: services: dhcpv6-client ssh ports: protocols: masquerade: no forward-ports: source-ports: icmp-blocks: rich rules:
In this listing, you can see that common operations related to the DHCP client and SSH are added to the zone.
Available Zones
To view the list of all zones, run this command:
# firewall-cmd --get-zones
I have got the following list:
block dmz drop external home internal public trusted work
To view the rules of a specific zone, add the -zone flag to the command:
# firewall-cmd --zone=home --list-all
home target: default icmp-block-inversion: no interfaces: sources: services: dhcpv6-client mdns samba-client ssh ports: protocols: masquerade: no forward-ports: source-ports: icmp-blocks: rich rules:
You can view the rules of all zones:
# firewall-cmd --list-all-zones
How to Change a Default Zone?
By default, all network interfaces are located in the public zone, but they can be moved to any zone with the command:
# firewall-cmd --zone=home —change-interface=eth0
Specify the zone you want after the –zone= parameter.
To change the default zone to home, run this command:
# firewall-cmd --set-default-zone=home
How to Add App Rules in FirewallD?
To open a port for an app, you can add the service as an exception. Here is how to display the list of available services:
# firewall-cmd --get-services
The output will contain a lot of services. The detailed information about a service is contained in its XML file. These files are located in /usr/lib/firewalld/services.
For example:
# cd /usr/lib/firewalld/services
# cat smtp.xml
<?xml version="1.0" encoding="utf-8"?> <service> <short>Mail (SMTP)</short> <description>This option allows incoming SMTP mail delivery. If you need to allow remote hosts to connect directly to your machine to deliver mail, enable this option. You do not need to enable this if you collect your mail from your ISP's server by POP3 or IMAP, or if you use a tool such as fetchmail. Note that an improperly configured SMTP server can allow remote machines to use your server to send spam.</description> <port protocol="tcp" port="25"/> </service>
The XML file contains the service description, the protocol and the number of port to be opened in firewalld.
When adding rules, you can use the –add-service parameter to allow firewall access to a specific service:
# firewall-cmd --zone=public --add-service=http
# firewall-cmd --zone=public --add-service=https
After adding rules, you can make sure if the services have been added to the specified zone:
# firewall-cmd --zone=public --list-services
dhcpv6-client http https ssh
If you want to make the rules permanent, use the –permanent parameter when adding them.
To remove a service from a zone:
# firewall-cmd --permanent --zone=public --remove-service=http
# firewall-cmd --zone=public --permanent --list-services
dhcpv6-client https ssh test
If you want to add your service to yj exceptions, you can create an XML file yourself and specify the data there. You can copy the data from any service and change the name, description and port number.
Copy smtp.xml to a directory for user services:
# cp /usr/lib/firewalld/services/smtp.xml /etc/firewalld/services
Change the service description in the file.
The XML file must also be renamed (I called my service test). Then restart firewalld and make sure your service appears in the list:
# firewall-cmd --get-services
syslog-tls telnet test tftp
Now you can add the service to any zone:
# firewall-cmd --zone=public --add-service=test --permanent
# firewall-cmd --zone=public --permanent --list-services
dhcpv6-client http https ssh test
If you have not found a service in the list, you can open the port you want in firewalld using this command:
# firewall-cmd --zone=public —add-port=77/tcp
— opens the TCP port 77
# firewall-cmd --zone=public —add-port=77/udp
— opens the UDP port 77
# firewall-cmd --zone=public —add-port=77-88/udp
— opens the UDP port range 77-88
# firewall-cmd --zone=public —list-ports
— displays the list of allowed ports
To block/allow ICMP requests:
# firewall-cmd --zone=public --add-icmp-block=echo-reply
# firewall-cmd --zone= public --remove-icmp-block=echo-reply
To remove an added port:
# firewall-cmd --zone=public —remove-port=77/udp
— removes a runtime rule for the UDP port 77
# firewall-cmd --permanent --zone=public —remove-port=77/udp
— removes a permanent rule
How to Create a New Zone in FirewallD?
You can create your own zone (I will call it our):
# firewall-cmd --permanent --new-zone=our
After creating a new zone, like after creating a service, you will need to restart firewalld:
# firewall-cmd --reload
# firewall-cmd --get-zones
block dmz drop external home internal our public trusted work
The our zone is available. You can add services to it or open some ports.
Firewalld: How to Block IP Addresses & Create Exceptions
You can add trusted IP addresses to firewalld exceptions or block unwanted IP addresses.
To add an IP address (e. g., 8.8.8.8) o the exceptions on your server using firewalld, run this command:
# firewall-cmd --zone=public --add-rich-rule='rule family="ipv4" source address="8.8.8.8" accept'
Check the zone and make sure that the IP address has been added to the exceptions in the rich-rules:
# firewall-cmd --zone=public --list-all
public (active) target: default icmp-block-inversion: no interfaces: eth0 sources: services: dhcpv6-client http https ssh test ports: protocols: masquerade: no forward-ports: source-ports: icmp-blocks: rich rules: rule family="ipv4" source address="8.8.8.8" accept
To block an IP address, replace accept with reject:
# firewall-cmd --zone=public --add-rich-rule='rule family="ipv4" source address="8.8.4.4" reject'
# firewall-cmd --zone=public --list-all
public (active) target: default icmp-block-inversion: no interfaces: eth0 sources: services: dhcpv6-client http https ssh test ports: protocols: masquerade: no forward-ports: source-ports: icmp-blocks: rich rules: rule family="ipv4" source address="8.8.8.8" accept rule family="ipv4" source address="8.8.4.4" reject
You can allow a service to accept request from the specific IP address only:
#firewall-cmd --permanent --add-rich-rule 'rule family="ipv4" source address="192.168.1.0/24" service name="https" accept'
If you want to quickly block all requests to your server, use the panic command:
# firewall-cmd --panic-on
You can disable the panic mode with this command:
# firewall-cmd --panic-off
Or by restarting your server.
You can block your firewalld configuration so that local services with the root privileges could not change the firewall rules you have created:
# firewall-cmd --lockdown-on
To disable the lockdown mode:
# firewall-cmd --lockdown-off
Configuring Port Forwarding with FirewallD
You can create a port forwarding rule in firewalld. To forward TCP port 443 to 9090:
# firewall-cmd --zone=public --add-forward-port=port=443:proto=tcp:toport=9090 --permanent
To remove a port forwarding rule:
# firewall-cmd --zone=public --remove-forward-port=port=443:proto=tcp:toport=9090