Mastering the Interplay Between Docker and Firewalld for Strict Network Isolation

The integration of Docker and firewalld represents one of the most complex networking challenges in modern Linux administration. At the core of this tension is a fundamental conflict between how Docker manages network traffic and how firewalld implements security policies. By default, Docker is designed for transparency and ease of use, which often means it prioritizes connectivity over strict security boundaries. For a standard workstation user, the seamless opening of ports is a feature; however, for a system administrator hardening a production server, this behavior can be catastrophic, as it effectively creates holes in the firewall that are invisible to the firewalld management tool.

The primary conflict arises because Docker interacts directly with the Linux kernel's packet filtering framework—iptables and nftables—by inserting its own chains and rules. Because these Docker-inserted rules are often processed before firewalld's filter rules, they can bypass the security policies defined via firewall-cmd. This creates a scenario where a port published via the -p flag in Docker is exposed to the global internet even if the firewalld "public" zone is configured to block all incoming traffic. Understanding how to reconcile these two systems requires a deep dive into the NAT (Network Address Translation) process, the specific configuration of the Docker daemon, and the strategic use of firewalld zones.

The Mechanics of the Docker and Firewalld Conflict

The friction between Docker and firewalld is rooted in the order of operations within the Linux kernel's networking stack. When a user publishes a port using Docker, the runtime creates NAT rules to forward traffic from the host's physical interface to the container's virtual interface.

The following technical breakdown explains the layers of this conflict:

  1. The NAT Priority Layer: Docker's NAT rules are processed before firewalld's filter rules. In a standard Linux networking flow, once a packet is handled by a NAT rule that forwards it to a destination, it may bypass the subsequent filtering logic that firewalld relies upon to block unauthorized access.
  2. The Direct Manipulation Layer: Docker does not use the firewalld API to request port openings; instead, it modifies iptables/nftables directly. This means that when you run firewall-cmd --list-all, you will not see the rules Docker has inserted, leading to a false sense of security where the admin believes a port is closed while it is actually open.
  3. The Bypass Effect: Because Docker adds its own chains to the iptables framework, it can route traffic around the standard firewalld zones. This is why users often report that firewalld rules are "completely ignored" when Docker containers are active.

This technical reality has a significant impact on the user. An administrator might configure a specific zone, such as a "test-from-home" zone, and restrict MySQL access to a single source IP. However, if a Docker container is running MySQL and publishing port 3306, that container may remain accessible to the entire world, regardless of the source IP restrictions set in firewalld.

Achieving Strict Filtering via Daemon Configuration

To regain absolute control over network traffic and force Docker to respect firewalld's policies, the automatic iptables management within Docker must be disabled. This shifts the responsibility of rule creation from the Docker daemon to the system administrator.

The process for implementing strict filtering is as follows:

  1. Modify the Docker Daemon Configuration: The administrator must edit the /etc/docker/daemon.json file to include the iptables: false directive.

json { "iptables": false }

  1. Execute a Full System Reboot: It is critical to understand that simply restarting the Docker service is insufficient. A full system reboot is required to ensure that all pre-existing iptables rules created by Docker during previous sessions are completely purged from the kernel.

```bash

reboot

```

  1. Verification of the State: Once the system has rebooted, Docker will no longer automatically create iptables rules. The immediate impact of this change is that containers will lose their default internet access. This is a planned failure that confirms the "Strict Filtering" mode is active. If a container cannot reach the internet after this change, it proves that the automatic holes previously punched in the firewall are gone.

This transition changes the operational context of the server. The administrator is no longer relying on "transparent" networking but is instead moving to an "explicit" networking model. Every single port that needs to be exposed must now be manually allowed through firewalld.

Advanced Firewalld Zone Strategies for Containers

When iptables: false is set, or when attempting to manage Docker within the firewalld ecosystem, the use of dedicated zones becomes the primary method of traffic control.

The "docker" zone is often utilized to manage the bridge network interfaces. For example, a configuration might show a zone named docker associated with interfaces such as docker0 or br-f7932280dd8a.

The technical properties of the docker zone are detailed in the following table:

Attribute Default Value/State Technical Purpose
Target default / ACCEPT Determines the default action for packets entering the zone
Interfaces docker0, br-XXXX Binds the zone to the virtual bridges created by Docker
Masquerade no / yes Controls whether the host masks the container IP as its own
ICMP Block Inversion no Standardizes how ping requests are handled

In a secure architecture, the "public" zone is used to manage inbound traffic from the internet, while the "docker" zone manages the internal traffic between the host and the containers. If an administrator wants to allow a specific container port to be reachable, they must now explicitly add that port to the public zone.

Example of allowing a container port manually:

bash firewall-cmd --permanent --zone=public --add-port=8443/tcp firewall-cmd --reload

Comparing Docker and Podman in the Firewalld Ecosystem

A significant distinction exists between Docker and Podman, particularly on RHEL-based systems. Podman is designed to be more compatible with the host's existing security infrastructure.

The operational differences are analyzed below:

  • Podman Integration: Podman, especially in rootless mode, does not bypass firewalld rules. It operates in a way that respects the existing firewall configuration, meaning standard firewall-cmd port rules work as expected without needing to disable internal iptables management.
  • Docker Integration: Docker's direct modification of iptables creates a "shadow" networking layer. This requires the manual intervention described in the daemon.json section to achieve the same level of predictability that Podman provides by default.

For users who require seamless integration and do not wish to manage complex iptables overrides, Podman is the recommended tool on RHEL 9. For those committed to Docker, the "Strict Filtering" approach is the only way to ensure that firewalld is the sole authority for network access.

Troubleshooting Connectivity and DNS Failures

Disabling Docker's iptables management can lead to unexpected side effects, most notably the loss of outbound connectivity and DNS resolution from within the container.

When iptables: false is applied, a user may encounter an error such as:

bash curl: (6) Could not resolve host: curl.se

This happens because the container's traffic is no longer being automatically masqueraded or routed by Docker's internal rules. To resolve this, the administrator must manually configure the networking requirements in firewalld.

The following steps are required to restore container internet access under strict filtering:

  1. Check and Enable IP Forwarding: The Linux kernel must be allowed to forward packets between the container interface and the physical interface.

bash sysctl net.ipv4.ip_forward

  1. Configure Masquerading: Masquerading must be enabled on the public zone to allow the container's private IP address to be translated to the host's public IP for outbound requests.

bash firewall-cmd --zone=public --query-masquerade firewall-cmd --zone=public --add-masquerade --permanent firewall-cmd --reload

  1. Verify the Docker Zone: Ensure the docker bridge interface is correctly assigned to a zone that allows traffic to flow toward the gateway.

Analysis of Security Postures and Best Practices

The conflict between Docker and firewalld presents two distinct security philosophies. The first is the "Transparent Model," where the user trusts the container runtime to manage its own ports. The second is the "Strict Model," where the user trusts only the system firewall.

The Transparent Model is risky because it obscures the actual state of the network. An administrator running firewall-cmd --list-all may see that port 80 is closed, while in reality, a Docker container is listening on port 80 and is fully accessible to the internet because Docker's rules are processed first. This creates a "hidden" attack surface.

The Strict Model, achieved by setting iptables: false, eliminates this shadow layer. It forces all traffic to pass through the firewalld filter. While this increases the administrative burden—requiring manual setup of masquerading and port forwarding—it provides absolute certainty regarding what traffic is entering and leaving the system.

For those who cannot disable iptables in Docker, an alternative "middle ground" is to use specific binding syntax. Instead of publishing a port globally, users can bind the port to the local loopback address:

bash docker run -p 127.0.0.1:8080:80 container_image

This prevents the port from being exposed to the external network regardless of the firewalld configuration, as the kernel will only accept connections originating from the host itself.

Conclusion

The relationship between Docker and firewalld is characterized by a fundamental struggle for control over the Linux kernel's packet filtering mechanisms. Docker's tendency to bypass firewalld by writing directly to iptables creates a security gap that can leave containers unintentionally exposed to the public internet.

To resolve this, the most robust solution is the implementation of strict filtering by disabling Docker's iptables management in the daemon.json file and performing a full system reboot. This transition shifts the system into a state where firewalld becomes the single point of truth for all networking rules. However, this shift necessitates a deeper understanding of Linux networking, as administrators must manually handle IP forwarding and masquerading to ensure that containers can still reach the internet.

Ultimately, the choice between Docker and Podman on RHEL-based systems often comes down to this very interaction. Podman's native respect for firewalld makes it a superior choice for security-conscious environments. For Docker users, the only path to true security is the abandonment of "transparent" networking in favor of a manually configured, firewalld-centric architecture.

Sources

  1. Strict Filtering of Docker Containers
  2. Configure firewalld Docker Podman Containers RHEL 9
  3. Securing Docker Ports to Local Access Only with Firewalld
  4. FirewallD doesn't go well with Docker #461
  5. Firewalld Blog
  6. Docker and firewalld could not resolve host from my containers

Related Posts