• Home
  • Blog
  • Getting started with firewalld

Getting started with firewalld

Vincent Danen

August 15, 2015

I'm mostly writing this for my own reference as I spent a bunch of time figuring this out while I was on holidays with some serious oVirt misadventures and didn't document any of what I did, so since I had to reinstall CentOS 7, I'm stuck doing this all over again.

Effectively I'm migrating from CentOS 6 to CentOS 7 and trying to take advantage of the new way of doing things. I could easily switch things to use /etc/sysconfig/iptables (that I can handle pretty much in my sleep) but it feels a bit like cheating, so I want to figure out firewalld which is to me a totally alien way of handling my firewall rules.

Suffice it to say that there may be better ways of doing this (and, to you the reader, probably far better tutorials), but this is how I went about it. This is on a CentOS 7.1 system.

First thing is to make sure firewalld is running and will run. It should be the default but never hurts to check:

[root@thor dhcp]# systemctl status firewalld
firewalld.service - firewalld - dynamic firewall daemon
   Loaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled)
   Active: active (running) since Sat 2015-08-15 18:21:30 MDT; 18min ago
 Main PID: 745 (firewalld)
...

Ok, it's active and enabled (in particular pay attention to the enabled bit that is bolded above) so on a reboot it will come up. firewalld has this concept of zones, so you can set certain ethernet interfaces to be assigned to a particular zone. The default zone is public, but as this is an internal DNS/DHCP/web server for my LAN, I want to set it to the internal zone:

[root@thor dhcp]# firewall-cmd --get-zones
block dmz drop external home internal public trusted work
[root@thor dhcp]# firewall-cmd --set-default-zone=internal
success

I also want to make sure that the one ethernet interface on this machine, enp2s0 (so long eth0!) is assigned the same zone. I believe this would happen by default, but it doesn't hurt to be explicit:

[root@thor dhcp]# firewall-cmd --zone=internal --change-interface=enp2s0 --permanent
success

Now we can see how this zone is configured:

[root@thor dhcp]# firewall-cmd --zone=internal --list-all
internal (default, active)
  interfaces: enp2s0
  sources:
  services: dhcpv6-client ipp-client mdns samba-client ssh
  ports:
  masquerade: no
  forward-ports:
  icmp-blocks:
  rich rules:

Not a lot there right now and it's definitely setup to be a workstation, not a server. You can see the available list of services that come pre-defined (they are XML files in /usr/lib/firewalld/services) by using:

[root@thor dhcp]# firewall-cmd --get-services

If you want to examine any of the listed services, just look at the XML file. For instance, /usr/lib/firewalld/services/dns.xml looks like:

<?xml version="1.0" encoding="utf-8"?>
<service>
  <short>DNS</short>
  <description>The Domain Name System (DNS) is used to provide and request host and domain names. Enable this option, if you plan to provide a domain name service (e.g. with bind).</description>
  <port protocol="tcp" port="53"/>
  <port protocol="udp" port="53"/>
</service>

Pretty straightforward. When adding new services or rules, firewalld makes them temporary, in that they will persist until a reboot or service restart. You need to use the "--permanent" option to, well, make them permanent. Since this server is going to do DNS/DHCP/HTTP/HTTPS we need to do:

[root@thor dhcp]# firewall-cmd --permanent --zone=internal --add-service=http
success
[root@thor dhcp]# firewall-cmd --permanent --zone=internal --add-service=https
success
[root@thor dhcp]# firewall-cmd --permanent --zone=internal --add-service=dns
success
[root@thor dhcp]# firewall-cmd --permanent --zone=internal --add-service=dhcp
success
[root@thor dhcp]# firewall-cmd --reload
success
[root@thor dhcp]# firewall-cmd --zone=internal --list-all
internal (default, active)
  interfaces: enp2s0
  sources:
  services: dhcp dhcpv6-client dns http https ipp-client mdns samba-client ssh
  ports:
  masquerade: no
  forward-ports:
  icmp-blocks:
  rich rules:

In the above we added four services: HTTP, HTTPS, DNS, and DHCP. We then reloaded the rules (so as to apply them) and then listed the internal zone where we can now see our new services are enabled.

If you want to enable a service for which no default service definition exists, you can create one in /etc/firewalld/services/ as an XML file (copy a similar one from /usr/lib/firewalld/services/ and adjust for your service). If you're using SELinux, be sure to run restorecon -Rv /etc/firewalld and make sure the XML file has 0640 permissions and is owned root:root.

Instead of making a new service, however, you can simply add ports to the configuration which might be easier. For instance, if I wanted to expose apcupsd but didn't want to make a service I might do:

[root@thor dhcp]# firewall-cmd --zone=internal --add-port=3551/udp --permanent
success
[root@thor dhcp]# firewall-cmd --zone=internal --add-port=3551/tcp --permanent
success
[root@thor dhcp]# firewall-cmd --reload
success
[root@thor dhcp]# firewall-cmd --zone=internal --list-all
internal (default, active)
  interfaces: enp2s0
  sources:
  services: dhcp dhcpv6-client dns http https ipp-client mdns samba-client ssh
  ports: 3551/udp 3551/tcp
  masquerade: no
  forward-ports:
  icmp-blocks:
  rich rules:

For further reading, I recommend:

In brief, managing the firewall is a little bit annoying to do this way compared to the old way of "vim /etc/sysconfig/iptables; service iptables restart" but I can understand why it's done this way now. It's quite modular and adaptable and allows you to make temporary changes to the firewall easily without having to know iptables commands. There are a lot of commands, and since firewalls tend not to be things you tinker with often, they may not be overly memorable (thus deciding to write this after my second time of doing it in as many weeks as I didn't remember a darn thing).

Leave a Comment

Comments use MarkDown. Need help? MarkDown Cheatsheet