firewalld is the firewall management daemon on RHEL, CentOS Stream, Fedora, SUSE, and their derivatives, providing a higher-level policy model and a runtime-safe management API on top of nftables (RHEL 8+ / Fedora 32+) or iptables (older systems). Its defining feature is runtime versus permanent configuration: firewall rule changes can be applied immediately to the running system without restarting the service or dropping existing connections (--runtime, the default), and separately persisted to disk so they survive reboots (--permanent). This two-phase model solves the operational problem that raw nftables or iptables rule changes traditionally required either accepting a momentary policy gap during reload or building custom transaction logic. The daemon exposes its API over D-Bus, allowing NetworkManager, libvirt, Podman, and other system components to request firewall policy changes programmatically — when a VM is started in libvirt or a container port is published in Podman, the respective tool calls firewalld over D-Bus to open the required port rather than directly manipulating nftables rules.
The policy model is built around zones: named security profiles that define the trust level of network traffic based on which network interface or source address range a packet arrives from. Each zone has a set of permitted services (named groups of ports and protocols — http, https, ssh, kubernetes-api, or custom-defined), permitted ports, masquerade settings, and forwarding rules. An interface or source is assigned to exactly one zone; traffic arriving on an unassigned interface falls to the default zone. RHEL ships nine predefined zones: drop (silently discard all inbound), block (reject inbound with ICMP messages), public (the conservative default for untrusted interfaces — allows only ssh and dhcpv6-client), external (for NAT masquerade on outbound-facing interfaces), dmz, work, home, internal (progressively more permissive), and trusted (accept all). A server in a datacenter would typically assign its primary NIC to public and then open specific services: firewall-cmd --add-service=https --permanent adds HTTPS to the current zone permanently. Rich rules extend the zone model with full match-and-action expressions covering source addresses, destination addresses, ports, protocols, connection state, and logging — allowing per-source-IP policy within a zone without requiring a new zone. Policies (introduced in firewalld 0.9) add inter-zone traffic control, allowing firewalld to express policy for traffic flowing between zones (for example, between a public interface and a trusted bridge interface in a VM host).
On RHEL-based Kubernetes nodes and OpenShift, firewalld coexists with the container networking stack in a carefully managed way. OpenShift’s installer configures firewalld zones for cluster nodes, opening the ports required by the Kubernetes API server, etcd, kubelet, and CNI communication, and adding the pod network CIDR to a trusted zone so that Kubernetes NetworkPolicy and iptables or nftables rules written by kube-proxy and the CNI plugin operate inside firewalld’s framework rather than conflicting with it. A common misconfiguration on RHEL Kubernetes nodes is disabling firewalld entirely to avoid conflicts, which removes host-level protection; the correct approach is to understand firewalld’s zone assignments and ensure the Kubernetes components and firewalld are configured to coexist. The firewall-cmd --list-all command shows the current zone’s effective configuration, and firewall-cmd --list-all-zones shows every zone’s policy — the standard starting point for diagnosing connectivity issues on RHEL-based nodes where firewalld is active. In SELinux-hardened environments, firewalld runs in its own SELinux domain (firewalld_t) with a narrow policy, complementing the kernel-level packet filtering it manages with process-level MAC confinement.
