• We value your experience with Plesk during 2024
    Plesk strives to perform even better in 2025. To help us improve further, please answer a few questions about your experience with Plesk Obsidian 2024.
    Please take this short survey:

    https://pt-research.typeform.com/to/AmZvSXkx
  • The Horde webmail has been deprecated. Its complete removal is scheduled for April 2025. For details and recommended actions, see the Feature and Deprecation Plan.
  • We’re working on enhancing the Monitoring feature in Plesk, and we could really use your expertise! If you’re open to sharing your experiences with server and website monitoring or providing feedback, we’d love to have a one-hour online meeting with you.

Question Securing Docker ports to local access only with firewalld

captainhook

Basic Pleskian
Server operating system version
CentOS 7
Plesk version and microupdate number
Plesk Obsidian 18.0.50 Update 2
Hi folks,

I am using Docker to run a few services, however I do NOT want the ports exposed to the internet. I am running CentOS 7 with firewalld, not Plesk's firewall product.

Does anyone know how to modify firewall rules using firewalld/firewall-cmd to block external access to Docker containers that are exposed?

There is a KB (https://support.plesk.com/hc/en-us/...-do-not-block-connections-to-Docker-container) which suggests adding iptables rules, however I am using firewalld and not plain iptables.

Here's my current firewall setup:
Code:
[root@n1 x]# firewall-cmd --list-all
plesk (active)
  target: default
  icmp-block-inversion: no
  interfaces: enp1s0
  sources:
  services: ssh
  ports: 22/tcp 21/tcp 80/tcp 443/tcp 54297/tcp
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:
        rule family="ipv4" source address="0.0.0.0/0" destination address="x.x.x.x/32" port port="8443" protocol="tcp" accept

I do have a firewall zone called 'docker', but I'm not entirely sure what it's doing:
Code:
[root@n1 x]# firewall-cmd --list-all-zones
....
docker (active)
  target: default
  icmp-block-inversion: no
  interfaces: br-f7932280dd8a docker0
  sources:
  services:
  ports:
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:
...

Thanks
 
In addition, I can add temporary iptables rules:
Code:
 iptables -I DOCKER-USER -d 172.17.0.0/16 -j DROP

However I can't save these since they're not being setup using firewalld, so after a reboot these rules get flushed.

From my search online, this seems like a long standing issue with Docker & iptables. It's insane that THIS is the default network/security configuration by Docker.
 
Don't really use docker all that much, and I mainly use docker stuff on one of my NAS for running things so it's behind a different firewall to begin with. Why docker does things the way it does I do not know. But from the looks of it you have 3 different options you can try from according to this post from serverfault: Why is firewalld allowing public traffic to my non-public ports, bound to Docker containers?

My suggestion is, if you're able to or if you're behind a separate firewall already, just make sure that the other firewall isn't forwarding all traffic to the server but only the required ports, this way the docker containers can do whatever they want while still behind the bubble.
 
Don't really use docker all that much, and I mainly use docker stuff on one of my NAS for running things so it's behind a different firewall to begin with. Why docker does things the way it does I do not know. But from the looks of it you have 3 different options you can try from according to this post from serverfault: Why is firewalld allowing public traffic to my non-public ports, bound to Docker containers?

My suggestion is, if you're able to or if you're behind a separate firewall already, just make sure that the other firewall isn't forwarding all traffic to the server but only the required ports, this way the docker containers can do whatever they want while still behind the bubble.
Unfortunately I don't have a firewall in front of this particular server I'm leasing. I understand in a corporate solution it would be insane to not have a fw fronting all of this and I wish more providers were bothered to layer a basic firewall in front of servers they lease out... I know OVH does on some of their lines, but majority of providers do not.

I will play around with firewall-cmd over the weekend and see if I can add a rich rule to my 'plesk' zone to overcome this.

Appreciate your engagement :)
 
No problem, hope you can work something out that will work for you.

And ye, I use Linode for where my server is located in and I just use the Plesk firewall extension for managing all my firewall needs since that's good enough for my needs. I don't have the docker extension installed since I don't have a need for it. If I did I'd either deploy a cloud firewall that Linode has to offer or use Azure lol.

But do let us know if you're able to work something out.
 
@captainhook We have a similar feature request, but it has not become popular so far, and we'd also need more input on it. Maybe you would like to add your comment to it and a link to this thread?
 
Thanks, Peter.

Update:
I tried to follow this guide (Securing Docker Ports with Firewalld (CentOS7, etc)) to recreate the DOCKER-USER chain but had to make a few changes. In future I will probably use Proxmox and then install Plesk inside a VM, that way I can control firewall at Proxmox level.

Code:
# 1. Stop Docker
systemctl stop docker.socket
systemctl stop docker.service

# 2. Recreate DOCKER-USER iptables chain with firewalld. Ignore warnings, do not ignore errors
firewall-cmd --permanent --direct --remove-chain ipv4 filter DOCKER-USER
firewall-cmd --permanent --direct --remove-rules ipv4 filter DOCKER-USER
firewall-cmd --permanent --direct --add-chain ipv4 filter DOCKER-USER

# 3. Add iptables rules to DOCKER-USER chain - unrestricted outbound, restricted inbound to private IPs
firewall-cmd --permanent --direct --add-rule ipv4 filter DOCKER-USER 1 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -m comment --comment 'Allow containers to connect to the outside world'
firewall-cmd --permanent --direct --add-rule ipv4 filter DOCKER-USER 1 -j RETURN -s 127.0.0.0/8 -m comment --comment 'allow internal docker communication, loopback addresses'
firewall-cmd --permanent --direct --add-rule ipv4 filter DOCKER-USER 1 -j RETURN -s 10.0.0.0/8 -m comment --comment 'allow internal docker communication, private range'
firewall-cmd --permanent --direct --add-rule ipv4 filter DOCKER-USER 1 -j RETURN -s 172.16.0.0/12 -m comment --comment 'allow internal docker communication, private range'
firewall-cmd --permanent --direct --add-rule ipv4 filter DOCKER-USER 1 -j RETURN -s 192.168.0.0/16 -m comment --comment 'allow internal docker communication, private range'

# 4. Block all other IPs. This rule has lowest precedence, so you can add rules before this one later.
firewall-cmd --permanent --direct --add-rule ipv4 filter DOCKER-USER 10 -j REJECT -m comment --comment 'reject all other traffic to DOCKER-USER'

# 5. Activate rules
firewall-cmd --reload

# 6. Start Docker
systemctl start docker.socket
systemctl start docker.service

This has worked for me so far.
 
I probably went overboard by adding all those private IP ranges, you can run `ip a` to find the IP addresses of your interfaces and use those instead to keep things stricter.

In most cases just 127.0.0.0/8 and 172.16.0.0/12 should be sufficient to cover your host loopback (127.0.0.1) and then your docker networks (172.x.x.x).
But if you want to expose it to your wider internal network, then consider adding 10.0.0.0/8 and 192.168.0.0/16.
 
Back
Top