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
- A CentOS 8 server.
- A user with
sudoprivileges.
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:
- Create a new XML file in the
/usr/lib/firewalld/servicesdirectory.
sudo touch /usr/lib/firewalld/services/new-service.xml - Enter the relevant details in the XML file and save.
- 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