Firewall Management#
Linux systems are often connected to the internet directly or indirectly via a firewall, but Linux itself also has a firewall built-in. This firewall is constantly being developed and upgraded, and it is not always easy to configure. For this firewalld
was created to be an uniform way to manage the firewall as a whole.
Linux 2.0 came with ipfwadm
and was replaced by ipchains
in Linux 2.2. With Linux 2.4, ipchains
was replaced by iptables
. Since a couple of years development has started to replace iptables
with nftables
to provide a more flexible and powerful firewall ready for the next decade. With nftables
, the firewall can be configured on the fly and should be able to work in environments with 10 Gbps or more network bandwidth.
A short introduction to firewalld#
Firewalld is the way to unify the iptables
and nftables
, and make the transition easier. Automation tools like Ansible understand the abstraction layer firewalld provides and playbooks should work as expected. Recent versions of Red Hat, CentOS and Fedora come by default with firewalld installed and enabled. Lets make sure firewalld
is installed and running.
# dnf install firewalld
# systemctl enable --now firewalld
As seen with systemd, also firewalld has been designed to be script friendly. Command firewall-cmd --state
allows you to check if the firewall is enabled on a system.
# firewall-cmd --state
running
In the previous example firewall-cmd
was already shown and it is the command line interface to the firewalld
daemon. Now that we have the firewall running, we can start configuring it. First we check all the active zones that are bound to which network interfaces.
# firewall-cmd --get-active-zones
public
interfaces: enp1s0
The example above shows that network interface enp1s0
is placed in the public
zone, but what is defined in the public
zone? With the option --list-all
we can see the rules that are defined in the public
zone. By default not a lot is defined in the public
zone, but services like cockpit
, dhcpv6-client
and ssh
are defined making the public
zone a very useful zone to start with.
# firewall-cmd --list-all --zone=public
public (active)
target: default
icmp-block-inversion: no
interfaces: enp1s0
sources:
services: cockpit dhcpv6-client ssh
ports:
protocols:
forward: no
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
What are firewall or network zones#
If we take the definition that the firewalld manpage says, a firewall zone is a collection of rules that are applied to a specific network interface. The public
zone is the default zone, and it is the zone that is used when no other zone is specified.
- Zones
A network or firewall zone defines the trust level of the interface used for a connection. There are several pre-defined zones provided by firewalld. Zone configuration options and generic information about zones are described in firewalld.zone(5)
But again, what is a zone and which one to select? The answer is simple as the zone defines the trust level of the interface used for a connection. If our server was directly connected to internet the dmz
zone would be used, but if we were connected to a router, the internal
zone would be used. By default a couple of zones are predefined, but you can add your own zones.
# firewall-cmd --get-zones
block dmz drop external home internal nm-shared public trusted work
All network interfaces are placed in the default network zone unless explicitly defined. With the option --get-default-zone
we can see the default zone.
# firewall-cmd --get-default-zone
public
The default zone can also be changed and will directly change for all the interfaces unless explicitly defined. If you make the default zone block
, then all unspecified interfaces will be placed in the block
zone and all network traffic will direct stop directly.
# firewall-cmd --get-default-zone dmz
success
# firewall-cmd --get-active-zones
dmz
interfaces: enp1s0
Note
The default zone in all examples will be public
unless otherwise specified.
# firewall-cmd --change-interface=<nic> [--zone=<ZONE>]
# firewall-cmd --get-zone-of-interface=enp1s0
public
# firewall-cmd --zone=dmz --list-interfaces
# firewall-cmd --zone=public --list-interfaces
enp1s0
Services#
$ firewall-cmd --get-services
RH-Satellite-6 RH-Satellite-6-capsule 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 collectd condor-collector ctdb dhcp dhcpv6 dhcpv6-client distcc dns dns-over-tls docker-registry docker-swarm dropbox-lansync elasticsearch etcd-client etcd-server finger foreman foreman-proxy freeipa-4 freeipa-ldap freeipa-ldaps freeipa-replication freeipa-trust ftp galera 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-api kube-apiserver kube-control-plane kube-controller-manager kube-scheduler kubelet-worker ldap ldaps libvirt libvirt-tls lightning-network llmnr managesieve matrix mdns memcache minidlna mongodb mosh mountd mqtt mqtt-tls ms-wbt mssql murmur mysql nbd netbios-ns 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 rquotad 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 tile38 tinc tor-socks transmission-client upnp-client vdsm vnc-server wbem-http wbem-https wireguard wsman wsmans xdmcp xmpp-bosh xmpp-client xmpp-local xmpp-server zabbix-agent zabbix-server
$ firewall-cmd --reload
$ firewall-cmd --add-service=oracle [--zone=<ZONE>]
$ firewall-cmd --add-service=oracle --zone=dmz --permanent
$ firewall-cmd --add-port=666/tcp
$ firewall-cmd --add-source=192.168.1.0/24
$ firewall-cmd --list-all
$ firewall-cmd --remove-port=666/tcp [--permanent] [--zone=<ZONE>]
$ firewall-cmd --remove-service=oracle [--permanent] [--zone=<ZONE>]
$ firewall-cmd --add-rich-rule `rule family=“ipv4” source address=“10.0.0.0/8” service name=“http” accept’
$ firewall-cmd --direct --add-rule ipv4 filter INPUT 0 -p tcp --dport 9000 -j ACCEPT
Runtime vs permanent and timeouts#
$ firewall-cmd --add-service=http --add-service=https
$ firewall-cmd --add-service=http --add-service=https --permanent
$ firewall-cmd --add-service=http --add-port=https/tcp
$ firewall-cmd --reload
$ firewall-cmd --add-service=http --add-service=https --timeout=<seconds>
Rich rules#
$ firewall-cmd --direct --permanent --add-chain ipv4 raw blacklist
$ firewall-cmd --direct --permanent --add-rule ipv4 raw PREROUTING 0 -s 192.168.0.0/24 blacklist
$ firewall-cmd --direct --permanent --add-rule ipv4 raw blacklist 0 -m limit --limit 1/min -j LOG --log-prefix "blacklist "
$ firewall-cmd --direct --permanent --add-rule ipv4 raw blacklist 1 -j DROP
Masquerading/NAT#
$ firewall-cmd --permanent --zone=work --add-masquerade
Port-forwarding#
$ firewall-cmd --permanent --add-rich-rule='rule family=ipv4 source address=192.168.0.0/24 forward-port port=3000 protocol=tcp to-port=22122'
$ firewall-cmd --add-forward-port=port=3000:proto=tcp:toport=22122:toaddr=192.168.0.4