FirewallD blocks connections to exposed ports in containers using docker-compose

Create a docker-compose.yml file that exposes one or more ports, for example:


version: "2"
services:
  www:
    image: aikain/simplehttpserver:0.1
    restart: always
    ports:
      - "9111:80"
    volumes:
      - "/tmp:/var/www"

Then spin it up:

docker-compose up -d

Now try to expose the ports on firewalld:


firewall-cmd --new-service=myservice
firewall-cmd --service=myservice --add-port=9111/tcp
firewall-cmd --add-service=myservice --zone=public

And try to connect to port 9111 from another machine on your network… you’ll see it is blocked.

I also tried this:


firewall-cmd --add-service=myservice --zone=docker

But it still doesn’t work. Disabling firewalld allows connections through.

Wierdly if you use plain docker and not docker-compose it seems to work fine.

Version info:


Information for package firewalld:
----------------------------------
Repository     : Main Repository (OSS)
Name           : firewalld
Version        : 1.1.1-1.2
Arch           : noarch
Vendor         : openSUSE
Installed Size : 458.9 KiB
Installed      : Yes
Status         : up-to-date
Source package : firewalld-1.1.1-1.2.src
Upstream URL   : https://www.firewalld.org
Summary        : A firewall daemon with D-Bus interface providing a dynamic firewall
Description    : 
    firewalld is a firewall service daemon that provides a dynamic customizable
    firewall with a D-Bus interface.




Information for package docker:
-------------------------------
Repository     : Main Repository (OSS)
Name           : docker
Version        : 20.10.14_ce-2.2
Arch           : x86_64
Vendor         : openSUSE
Installed Size : 131.7 MiB
Installed      : Yes
Status         : up-to-date
Source package : docker-20.10.14_ce-2.2.src
Upstream URL   : http://www.docker.io
Summary        : The Moby-project Linux container runtime
Description    : 
    Docker complements LXC with a high-level API which operates at the process
    level. It runs unix processes with strong guarantees of isolation and
    repeatability across servers.


    Docker is a great building block for automating distributed systems: large-scale
    web deployments, database clusters, continuous deployment systems, private PaaS,
    service-oriented architectures, etc.





I cannot reproduce it. Your example works after your docker-compose command here. Both docker and docker-compose are from standard repositories (using python 3.8).

P.S. actually I was rather surprised it worked (without any manual steps - I did not expect it). For the sake of archives:

  1. firewalld allows incoming/forwarded dnat’ed packets:
        chain filter_INPUT {
...
                ct status dnat accept
...
        }


        chain filter_FORWARD {
...
                ct status dnat accept
...
        }
  1. docker adds iptables DNAT rule for ports forwarded to containers
  2. DNAT iptables rules are evaluated before firewalld nftables filter rules
  3. So firewalld nftables rules accept packets that were DNAT’ed by iptables

At least, that is the only explanation that I have.

Anyway, learned something new :slight_smile:

P.P.S. of course, if using legacy iptables backend for firewalld this is expected to work. But so far my understanding was that it is impossible to use raw iptables to allow something prohibited by firewalld nftables rules. I was wrong :slight_smile:

Docker containers are also exposed in the local network here, no need to do anything special. Review this doc, have you done this steps on your system? https://docs.docker.com/network/iptables/#prevent-docker-from-manipulating-iptables

Podman rootless containers are blocked as one would expect.