Maab S.
8min Read

Configure CentOS 8 Firewall with firewalld and firewall-cmd

config firewall with firewalld on CentOS

A firewall is one of the most fundamental ways to monitor and filter incoming and outgoing traffic. A set of inbound and outbound rules defined within firewall settings, determine which traffic to allow or block.

On CentOS and other Linux distros, firewalld is the default firewall management software. In the following tutorial, we will start by discussing the basic firewalld concepts, and then use it to configure a firewall on CentOS 8.

Get to know firewalld

Before we start playing around with firewalld, let’s first get to know it better.

Zones in firewalld

Firewalld has a set of predefined rules, known as zones, which help you define the level of trust you have in a particular network. Associating a network interface with a zone determines the nature of allowed behavior. To understand this a bit better, let’s look at a few default firewalld zones:

  • Trusted: Highest level of trust. Allow incoming and outgoing traffic to all the machines in this network.
  • Home: For home networks. Trust all the other machines on the network. Allow only a few incoming connections.
  • Work: For work environments. Trust all machines, and allow only approved incoming connections.
  • External: Configured when using firewall as a gateway. NAT masquerading is used to ensure that the internal network topology is hidden, but the servers are still reachable.
  • Public: Trust no-one by default. Allow a handful of incoming connections, based on need.
  • Drop: Lowest trust level. Drop every incoming packet without replying. Only allow outgoing traffic.

Firewall-cmd

Firewall-cmd is the command-line utility for the firewalld daemon. It’s used to define or change the firewalld configurations.

Services in firewalld

Services are a set of existing rules that can be applied within a zone. They are a great way to apply different rules, all at once. We will explore these in more detail in later sections.

Runtime vs permanent settings in firewalld

Firewalld allows you to define two kinds of settings: runtime and permanent. Runtime is the currently running configuration, which is reverted to the permanent configuration-set upon reboot.

By default, when you use firewall-cmd to configure your firewall, the changes are made to the runtime configuration set. To make changes permanent, you can add the --permanent option to the command.

Configure firewalld on CentOS 8

Now that we are somewhat acquainted with firewalld, let’s start configuring it on a CentOS 8 machine.

Prerequisites

Install and enable firewalld

Firewalld comes pre-installed in most Linux distributions, including CentOS 8. To confirm, run:

sudo yum list installed | grep firewalld

If firewalld is installed on your machine, you should get some output like below.

 firewalld.noarch                     0.8.0-4.el8                           @anaconda
 firewalld-filesystem.noarch          0.8.0-4.el8                           @anaconda

If you don’t get anything, then run the following command to install firewalld:

sudo yum install firewalld

The next step is to enable firewalld and make it start at boot. To do so, run:

sudo systemctl enable firewalld

Finally, reboot your machine:

reboot

Once your server reboots, use the following command to verify that firewalld is indeed running:

sudo firewall-cmd –state

You should see the server output running.

Get to know the defaults

Now, let’s try to explore the currently active firewalld configurations.

To see the default zone:

sudo firewall-cmd --get-default-zone

You should see that public is set.

To see the active zones:

sudo firewall-cmd --get-active-zones

Since we haven’t set any other zone yet, this should also give us public.

Output
public
   interfaces: ens3

We can also see that our only network interface on the server ens3 is currently being managed in the public zone.

To see all the rules applicable to the pubic zone, run:

sudo firewall-cmd --list-all
Output
public (active)                                                                                                                      
 target: default                                                                                                         
 icmp-block-inversion: no                                                                                                
 interfaces: ens3                                                                                                        
 sources:                                                                                                                
 services: cockpit dhcpv6-client ssh                                                                   
 ports:                                                                                                                  
 protocols:                                                                                                              
 masquerade: no                                                                                                          
 forward-ports:                                                                                                          
 source-ports:                                                                                                           
 icmp-blocks:                                                                                                            
 rich rules:                                                                                                                                                                                                                                     

We can see, among other things, that the rules allow for direct SSH into the machine via the ens3 interface.

To see the other available zones, run:

sudo firewall-cmd --get-zones
block dmz drop external home internal public trusted work

You can also see the default rules for each zone. E.g., to view all the rules for the zone home:

sudo firewall-cmd --zone=home --list-all
Output
home
target: default                                                                                                         
 icmp-block-inversion: no                                                                                                
 interfaces:                                                                                                        
 sources:                                                                                                                
 services: cockpit dhcpv6-client mdns samba-client ssh                                                                   
 ports:                                                                                                                  
 protocols:                                                                                                              
 masquerade: no                                                                                                          
 forward-ports:                                                                                                          
 source-ports:                                                                                                           
 icmp-blocks:                                                                                                            
 rich rules:         

Change the default zone

The default zone applies to everything that’s not explicitly assigned to any zone. E.g., if there is a source, network interface, or connection that can’t be bound to any configured zones, firewalld will use the default zone rules for it.

To change the default zone:

sudo firewall-cmd --set-default-zone=home
Output
success

Check:

sudo firewall-cmd --get-default-zone
Output
home

Change the zone for an interface

To change the zone for an interface:

sudo firewall-cmd --zone=internal --change-interface=ens3

The above command will activate the zone internal for the interface ens3.

Output
success

Change a zone’s target

A zone’s target defines its default behaviour, when dealing with incoming traffic that can’t be categorized, according to any specified rule. A target can either be DROP, ACCEPT, REJECT, or default.

To change a zone’s target, you could use the following command:

sudo firewall-cmd --zone=internal --set-target=DROP

This will set the target for the internal zone to DROP.

Create a custom zone

Firewalld also gives you the flexibility to define your own zone. This comes in very handy while defining application-specific rules.

To create a new zone named redis:

sudo firewall-cmd --new-zone=redis --permanent

We will also open a TCP port and allow access from only one source IP. Both these rules will be made permanent.

sudo firewall-cmd --zone=redis --add-port=10003/tcp --permanent
sudo firewall-cmd --zone=redis --add-source=192.168.123.1/32 --permanent

Finally, restart the firewalld daemon to apply the changes:

sudo firewall-cmd reload
Output for all 4 above commands
success

Apply services to a zone

Services allow us to apply a set of rules within a zone. Just like zones, there are some default services that you can use. To see them all:

sudo firewall-cmd --get-services
RH-Satellite-6 amanda-client amanda-k5-client amqp amqps apcupsd audit
 bacula bacula-client bb bgp bitcoin bitcoin-rpc bitcoin-testnet
 bitcoin-testnet-rpc bittorrent-lsd ceph ceph-mon cfengine cockpit
 condor-collector ctdb dhcp dhcpv6 dhcpv6-client distcc dns
 dns-over-tls docker-registry docker-swarm dropbox-lansync
 elasticsearch etcd-client etcd-server finger freeipa-4 freeipa-ldap
 freeipa-ldaps freeipa-replication freeipa-trust ftp ganglia-client
 ganglia-master git grafana gre high-availability http https imap
 imaps ipp ipp-client ipsec irc ircs iscsi-target isns jenkins kadmin
 kdeconnect kerberos kibana klogin kpasswd kprop kshell kube-apiserver
 ldap ldaps libvirt libvirt-tls lightning-network llmnr managesieve
 matrix mdns memcache minidlna mongodb mosh mountd mqtt mqtt-tls
 ms-wbt mssql murmur mysql nfs nfs3 nmea-0183 nrpe ntp nut openvpn
 ovirt-imageio ovirt-storageconsole ovirt-vmconsole plex pmcd pmproxy
 pmwebapi pmwebapis pop3 pop3s postgresql privoxy prometheus
 proxy-dhcp ptp pulseaudio puppetmaster quassel radius rdp redis
 redis-sentinel rpc-bind rsh rsyncd rtsp salt-master samba
 samba-client samba-dc sane sip sips slp smtp smtp-submission smtps
 snmp snmptrap spideroak-lansync spotify-sync squid ssdp ssh
 steam-streaming svdrp svn syncthing syncthing-gui synergy syslog
 syslog-tls telnet tentacle tftp tftp-client tile38 tinc tor-socks
 transmission-client upnp-client vdsm vnc-server wbem-http wbem-https
 wsman wsmans xdmcp xmpp-bosh xmpp-client xmpp-local xmpp-server
 zabbix-agent zabbix-server

To view more information about the services, you can read the respective xml configuration files present in the /usr/lib/firewalld/services directory using less and appending directory with a filename (listed below)

less /usr/lib/firewalld/services/filename.xml

Example command

sudo less /usr/lib/firewalld/services/grafana.xml

To view the full list of files below, run

sudo ls /usr/lib/firewalld/services
Ouput
amanda-client.xml        grafana.xml            mysql.xml                 slp.xml                                  amanda-k5-client.xml     gre.xml                new-service.xml           smtp-submission.xml                      amqps.xml                high-availability.xml  nfs3.xml                  smtps.xml                                amqp.xml                 https.xml              nfs.xml                   smtp.xml                                 apcupsd.xml              http.xml               nmea-0183.xml             snmptrap.xml                             audit.xml                imaps.xml              nrpe.xml                  snmp.xml                                 bacula-client.xml        imap.xml               ntp.xml                   spideroak-lansync.xml                    bacula.xml               ipp-client.xml         nut.xml                   spotify-sync.xml                         bb.xml                   ipp.xml                openvpn.xml               squid.xml                                bgp.xml                  ipsec.xml              ovirt-imageio.xml         ssdp.xml                                 bitcoin-rpc.xml          ircs.xml               ovirt-storageconsole.xml  ssh.xml                                  bitcoin-testnet-rpc.xml  irc.xml                ovirt-vmconsole.xml       steam-streaming.xml                      bitcoin-testnet.xml      iscsi-target.xml       plex.xml                  svdrp.xml                                bitcoin.xml              isns.xml               pmcd.xml                  svn.xml                                  bittorrent-lsd.xml       jenkins.xml            pmproxy.xml               syncthing-gui.xml                        ceph-mon.xml             kadmin.xml             pmwebapis.xml             syncthing.xml                            ceph.xml                 kdeconnect.xml         pmwebapi.xml              synergy.xml                              cfengine.xml             kerberos.xml           pop3s.xml                 syslog-tls.xml                           cockpit.xml              kibana.xml             pop3.xml                  syslog.xml                               condor-collector.xml     klogin.xml             postgresql.xml            telnet.xml                               ctdb.xml                 kpasswd.xml            privoxy.xml               tentacle.xml                             dhcpv6-client.xml        kprop.xml              prometheus.xml            tftp-client.xml                          dhcpv6.xml               kshell.xml             proxy-dhcp.xml            tftp.xml                                 dhcp.xml                 kube-apiserver.xml     ptp.xml                   tile38.xml                               distcc.xml               ldaps.xml              pulseaudio.xml            tinc.xml                                 dns-over-tls.xml         ldap.xml               puppetmaster.xml          tor-socks.xml                            dns.xml                  libvirt-tls.xml        quassel.xml               transmission-client.xml                  docker-registry.xml      libvirt.xml            radius.xml                upnp-client.xml                          docker-swarm.xml         lightning-network.xml  rdp.xml                   vdsm.xml                                 dropbox-lansync.xml      llmnr.xml              redis-sentinel.xml        vnc-server.xml                           elasticsearch.xml        managesieve.xml        redis.xml                 wbem-https.xml                           etcd-client.xml          matrix.xml             RH-Satellite-6.xml        wbem-http.xml                            etcd-server.xml          mdns.xml               rpc-bind.xml              wsmans.xml                               finger.xml               memcache.xml           rsh.xml                   wsman.xml                                freeipa-4.xml            minidlna.xml           rsyncd.xml                xdmcp.xml                                freeipa-ldaps.xml        mongodb.xml            rtsp.xml                  xmpp-bosh.xml                            freeipa-ldap.xml         mosh.xml               salt-master.xml           xmpp-client.xml                          freeipa-replication.xml  mountd.xml             samba-client.xml          xmpp-local.xml                           freeipa-trust.xml        mqtt-tls.xml           samba-dc.xml              xmpp-server.xml                          ftp.xml                  mqtt.xml               samba.xml                 zabbix-agent.xml                         ganglia-client.xml       mssql.xml              sane.xml                  zabbix-server.xml                        ganglia-master.xml       ms-wbt.xml             sips.xml                                                           git.xml                  murmur.xml             sip.xml

To add a service to a zone, use:

sudo firewall-cmd --zone=internal --add-service=http
Output
success

Above command will allow http traffic on all the interfaces in the internal zone.

Similarly, if you are planning to use your server as a DNS, you can add the DNS service:

sudo firewall-cmd --zone=internal --add-service=dns
Output
success

Create a custom service

Just like you can create a custom zone, you can also create a custom service. Here are the steps:

  1. Create a new XML file in the /usr/lib/firewalld/services directory.
    sudo touch /usr/lib/firewalld/services/new-service.xml
  2. Enter the relevant details in the XML file and save.
  3. Reload the firewalld daemon so that it notices the newly created service. sudo firewall-cmd reload

You should now be able to apply the new service, just like any other.

Open IPs and ports

To enable all incoming traffic from an IP address or range, within a zone, without having to create a new service:

sudo firewall-cmd --zone=internal --add-source=192.168.123.1 --permanent

To remove the IP, just replace --add-source with --remove-source.

sudo firewall-cmd --zone=internal --remove-source=192.168.123.1 --permanent

Similarly, if you want to allow all incoming traffic on a specific port:

sudo firewall-cmd --zone=internal --add-port=8081/tcp --permanent

and to remove the port:

sudo firewall-cmd --zone=internal --remove-port=8081/tcp --permanent
Output
success

Save runtime configurations permanently

If at any time you wish to persist your runtime settings, before a reboot washes them away, you can use the following command:

sudo firewall-cmd --runtime-to-permanent
Output
success

The Author

Maab S.

Maab is an experienced software engineer who specializes in explaining technical topics to a wider audience.

More posts from Maab