firewall integration in Cisco ACI#

(do a blog search for “service_insertion”)

firewalls in Linux#

The default host-based firewall in RHEL allows all outgoing connections and blocks all incoming ones, except those explicitely permitted.

The firewall daemon is called firewalld. To interact with it, use the firewall-cmd tool. The firewalld daemon translates the instructions of firewall-cmd into policies that use the syntax of the kernel’s netfilter and nftables.

firewall rules#

A rule dictates that a service is allowed to be accessed by an inbound connection. A firewalld service is added with firewall-cmd --add-service or removed with firewall-cmd --remove-service.

firewalld models#

There is no static file that describes the current active firewall rules. This is because firewalld has two internal representations, or models:

  • the runtime in-memory model: this model describes what firewalld considers to be active in the present moment. It is built for the first time from the permanent in-memory model files: /etc/firewalld/zones/ (the file that corresponds to whatever default zone is configured) and etc/firewalld/services/ (any custom service definition for any services that are referenced by name in the zone file). At system reboot, firewalld.service restart or firewall-cmd --reload, the runtime in-memory model is built using the same files again.
  • the permanent in-memory model: this model describes what firewalld expects to see at system reboot, firewalld.service reload or firewall-cmd --reload. Including the option --permanent in the firewall-cmd command triggers a serialization in the XML files mentioned above (i.e. disk write operations).

Services#

A firewalld service is and object that is declared by an XML file that contains ports and transport protocols data. All firewalld services are located at /usr/lib/firewalld/services/. But this does not imply that they are enabled for inbound connections. They are definitions that are available for all zones of the firewalld. What enables or disables a firewalld services is an added or removed rule.

user1@rhel10-vm2:~$ ls /usr/lib/firewalld/services/
0-AD.xml                 jenkins.xml                         RH-Satellite-6-capsule.xml
afp.xml                  kadmin.xml                          RH-Satellite-6.xml
alvr.xml                 kdeconnect.xml                      rootd.xml
amanda-client.xml        kerberos.xml                        rpc-bind.xml
amanda-k5-client.xml     kibana.xml                          rquotad.xml
amqps.xml                klogin.xml                          rsh.xml
amqp.xml                 kpasswd.xml                         rsyncd.xml
anno-1602.xml            kprop.xml                           rtsp.xml
anno-1800.xml            kshell.xml                          salt-master.xml
apcupsd.xml              kube-apiserver.xml                  samba-client.xml
aseqnet.xml              kube-api.xml                        samba-dc.xml
audit.xml                kube-controller-manager-secure.xml  samba.xml
ausweisapp2.xml          kube-controller-manager.xml         sane.xml
bacula-client.xml        kube-control-plane-secure.xml       settlers-history-collection.xml
bacula.xml               kube-control-plane.xml              sips.xml

<---- output omitted ---->

Example of a service file:

user1@rhel10-vm2:~$ cat /usr/lib/firewalld/services/https.xml
<?xml version="1.0" encoding="utf-8"?>
<service>
  <short>Secure WWW (HTTPS)</short>
  <description>HTTPS is a modified HTTP used to serve Web pages when security is important. Examples are sites that require logins like stores or web mail. This option is not required for viewing pages locally or developing Web pages. You need the httpd package installed for this option to be useful.</description>
  <port protocol="tcp" port="443"/>
</service>
user1@rhel10-vm2:~$ 

There is also the /etc/firewalld/services tree path. This is the directory to place user-defined services (user-defined XML files) in, when I want to shadow a particular firewalld service in /usr/lib/firewalld/services/. Example, I create a ssh.xml service file and place it in /etc/firewalld/services/ to shadow the /usr/lib/firewalld/services/ssh.xml file.

user1@rhel10-vm2:~$ sudo ls /etc/firewalld/services/
[sudo] password for user1: 
user1@rhel10-vm2:~$ 

confusion risk 1#

The file /etc/services contains a definition of services that look similar to firewalld service definition files. But /etc/services serves general use; It defines the services that are called out by name by certain applications. #QA when would firewalld use the /etc/services/?

# /etc/services:
# $Id: services,v 1.49 2017/08/18 12:43:23 ovasik Exp $
#
# Network services, Internet style
# IANA services version: last updated 2021-01-19
#
# Note that it is presently the policy of IANA to assign a single well-known
# port number for both TCP and UDP; hence, most entries here have two entries
# even if the protocol doesn't support UDP operations.
# Updated from RFC 1700, ``Assigned Numbers'' (October 1994).  Not all ports
# are included, only the more common ones.
#
# The latest IANA port assignments can be gotten from
#       http://www.iana.org/assignments/port-numbers
# The Well Known Ports are those from 0 through 1023.
# The Registered Ports are those from 1024 through 49151
# The Dynamic and/or Private Ports are those from 49152 through 65535
#
# Each line describes one service, and is of the form:
#
# service-name  port/protocol  [aliases ...]   [# comment]

tcpmux          1/tcp                           # TCP port service multiplexer
tcpmux          1/udp                           # TCP port service multiplexer
rje             5/tcp                           # Remote Job Entry
rje             5/udp                           # Remote Job Entry
echo            7/tcp
echo            7/udp
discard         9/tcp           sink null
discard         9/udp           sink null
systat          11/tcp          users
systat          11/udp          users
daytime         13/tcp

<---- output omitted ---->

operations on firewalld services#

A firewalld service is allowed or denied in either the runtime model (the ruleset in memory) aka the in-memory model, or in the permanent in-memory model.

List open services:

user1@rhel10-vm2:~$ sudo firewall-cmd --list-services
[sudo] password for user1: 
cockpit dhcpv6-client ssh
user1@rhel10-vm2:~$ 

Remove a service from the runtime, i.e. after a system reboot the rule is deleted. I removed the SSH service for instance:

user1@rhel10-vm2:~$ sudo firewall-cmd --remove-service=ssh
success
user1@rhel10-vm2:~$ sudo firewall-cmd --list-services
cockpit dhcpv6-client
user1@rhel10-vm2:~$ 

and proved that the machine can no longer be accessed with SSH:

user1@rhel10-vm1:~$ ping 192.168.122.6
PING 192.168.122.6 (192.168.122.6) 56(84) bytes of data.
64 bytes from 192.168.122.6: icmp_seq=1 ttl=64 time=0.432 ms
64 bytes from 192.168.122.6: icmp_seq=2 ttl=64 time=0.518 ms
^C
--- 192.168.122.6 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1018ms
rtt min/avg/max/mdev = 0.432/0.475/0.518/0.043 ms
user1@rhel10-vm1:~$
user1@rhel10-vm1:~$ ssh [email protected]
ssh: connect to host 192.168.122.6 port 22: No route to host
user1@rhel10-vm1:~$

Adding SSH again to the list of open services:

user1@rhel10-vm2:~$ sudo firewall-cmd --add-service=ssh
success
user1@rhel10-vm2:~$ 

and retrying access via SSH:

user1@rhel10-vm1:~$ ssh [email protected]
The authenticity of host '192.168.122.6 (192.168.122.6)' can't be established.
ED25519 key fingerprint is SHA256:vHOUVnOMr0tQamHlOmyd1hkVUXK8yZLUfSkiUHipjEw.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? 

zones#

A firewalld zone contains the services that are allowed in inbound connections. The services are referenced by name. The service definition is, as explained above, in /usr/lib/firewalld/services/ and /etc/firewalld/services/ for system-based and user-based files respectively.

List the system-defined zones:

user1@rhel10-vm2:~$ ls /usr/lib/firewalld/zones/
block.xml  drop.xml      home.xml      nm-shared.xml  trusted.xml
dmz.xml    external.xml  internal.xml  public.xml     work.xml
user1@rhel10-vm2:~$ ls -l /usr/lib/firewalld/zones/
total 40
-rw-r--r--. 1 root root 312 Jun 10  2025 block.xml
-rw-r--r--. 1 root root 306 Jun 10  2025 dmz.xml
-rw-r--r--. 1 root root 304 Jun 10  2025 drop.xml
-rw-r--r--. 1 root root 317 Jun 10  2025 external.xml
-rw-r--r--. 1 root root 410 Jun 10  2025 home.xml
-rw-r--r--. 1 root root 425 Jun 10  2025 internal.xml
-rw-r--r--. 1 root root 729 Feb 28  2025 nm-shared.xml
-rw-r--r--. 1 root root 356 Jun 10  2025 public.xml
-rw-r--r--. 1 root root 175 Jun 10  2025 trusted.xml
-rw-r--r--. 1 root root 352 Jun 10  2025 work.xml
user1@rhel10-vm2:~$ 

List the user-defined zones:

user1@rhel10-vm2:~$ ls -l /etc/firewalld/zones
ls: cannot access '/etc/firewalld/zones': Permission denied
user1@rhel10-vm2:~$ ls -l /etc/firewalld/
ls: cannot open directory '/etc/firewalld/': Permission denied
user1@rhel10-vm2:~$ sudo ls -l /etc/firewalld/zones/
[sudo] password for user1: 
total 8
-rw-r--r--. 1 root root 356 Nov 15  2025 public.xml
-rw-r--r--. 1 root root 356 Nov 15  2025 public.xml.old
user1@rhel10-vm2:~$ 

Get the defaut zone ( #QA what is the default zone for?) and change its value:

user1@rhel10-vm2:~$ firewall-cmd --get-default-zone
public
user1@rhel10-vm2:~$ firewall-cmd --list-zones
usage: 'firewall-cmd --help' for usage information or see firewall-cmd(1) man page
firewall-cmd: error: unrecognized arguments: --list-zones
user1@rhel10-vm2:~$ man firewall-cmd 
user1@rhel10-vm2:~$ firewall-cmd --get-zones
block dmz drop external home internal nm-shared public trusted work
user1@rhel10-vm2:~$ sudo firewall-cmd --set-default-zone drop
success
user1@rhel10-vm2:~$ firewall-cmd --get-default-zone
drop
user1@rhel10-vm2:~$ 

To avoid ambiguity, I dedide to always include the zone name in firewall-cmd command lines. I do not want to rely on convenience and risk mixing rules between zones.