What are proper iptables Rules for Docker Host?

17,342

Solution 1

I can't access the internet from within containers (if I put iptables: false in Docker's daemon.json config file)

Docker relies on iptables to configure its networking. This includes NAT rules to handle access to and from the external network, and lots of other rules to configure containers access to each other on docker networks. By default, this access is open, but there are options when creating networks to restrict outside access and inter container communication. Therefore I do not recommend setting the iptables option to false in docker since that will break all of that functionality as you've seen.

Publishing a port on the host implicitly allows access from outside. So the easiest option to avoid outside access is to not publish the port. You could publish the port onto a specific interface, e.g. 127.0.0.1:8080:80 which would publish the port 8080 on the host's loopback interface (127.0.0.1) to connect to a container's port 80, and that loopback interface is not externally accessible. However, if leaving the port unpublished is not an option, it is possible to do this with iptables.

What I want at this point is to find out is it possible to use iptables to block the ports opened by Docker and how

This can be done by modifying the DOCKER-USER filter chain. You can find examples of this, like:

$ iptables -I DOCKER-USER -i ext_if ! -s 192.168.1.0/24 -j DROP

from the following docs: https://docs.docker.com/network/iptables/

Note that the port is changed by some mangling rules that run before the filter rules, so if you want to filter by port, you'll need to use conntrack to get the original destination port:

$ iptables -I DOCKER-USER -i eth0 -p tcp \
    -m conntrack --ctorigdstport 8080 -j DROP
$ iptables -I DOCKER-USER -i eth0 -s 10.0.0.0/24 -p tcp \
    -m conntrack --ctorigdstport 8080 -j ACCEPT

Note that there is a default rule in DOCKER-USER to accept all, so you'll want to insert rules at the top of the chain (-I) rather than appending to the end (-A).

See: Steps for limiting outside connections to docker container with iptables?

Solution 2

What I want at this point is to find out is it possible to use iptables to block the ports opened by Docker and how (via mangle prerouting perhaps?).

After a lot of research and tests, I found out that the best (and easiest) way to expose only the ports you want and don't expose docker ports is to set the IP in docker-compose.yml to 127.0.0.1 (expose only to the host)

ports:
  - "127.0.0.1:3306:3306"

Then you can use nginx or any other reverse proxy to expose to the outside.

This way:

  • You don't need to add DOCKER-USER iptables rules everytime you restart docker
  • Port 3306 is exposed only inside the host
  • Docker can manage iptables rules as it wants.
Share:
17,342

Related videos on Youtube

dzhi
Author by

dzhi

CTO, DevOps & Technical SEO at Four Dots

Updated on September 18, 2022

Comments

  • dzhi
    dzhi over 1 year

    I have Ubuntu server with Docker to serve MySQL and SSH/SFTP and I need all ports except 3306 and 22 to be firewalled, pretty standard and trivial requirement, right?

    Now, I managed to find a sort of solution but it doesn't work fully for me as after applying it, either:

    1. I can't access any of the mentioned services (by default)
    2. I can't access the internet from within containers (if I put iptables: false in Docker's daemon.json config file)

    I tried a number of other search results but they're mostly so complex that I don't understand what they're doing or they're heavily scripted making me, an iptables layman, an impossible task to take something from it.

    Proposed solution looks rather simple and easy to comprehend but entire Docker networking complexity makes it much harder to debug.

    Can someone please share their working iptables rules for Docker hosts or at least guide me in right direction?

    I use docker-compose to launch services and this is my yaml:

    version: '3.7'
    
    services:
      mysql:
        container_name: 'mysql'
        image: mysql:8.0.13
        command: --default-authentication-plugin=mysql_native_password
        user: 1000:1000
        ports:
          - "3306:3306"
        volumes:
          - ./data:/var/lib/mysql
          - ./config/custom.cnf:/etc/mysql/conf.d/custom.cnf
        networks:
          - database
        restart: always
    
    networks:
      database:
        driver: bridge
    

    Edit: What I found is that allowing Docker to manage iptables rules is recommended and less demanding, at least in a long term and its okay to let Docker open required ports even though I didn't do that in a way I prefer, its still valid. What I want at this point is to find out is it possible to use iptables to block the ports opened by Docker and how (via mangle prerouting perhaps?). Any suggestions? Thanks a ton!

    • BMitch
      BMitch over 5 years
      Do you restart the docker engine after changing iptables?
    • dzhi
      dzhi over 5 years
      @BMitch Absolutely. Thing is that rules from the article above are made so that Docker workloads docnot need tocbe restarted after making changes to the firewall. Got any rules to share?
    • BMitch
      BMitch over 5 years
      I typically configure a host with some default restrictive rules, and then start docker. Biggest thing for me is to add ports for swarm mode. For me, it just works from there.
    • BMitch
      BMitch over 5 years
      Make sure you don't have anything else mucking with the iptables entries, like firewalld.
    • dzhi
      dzhi over 5 years
      No, I'm running Ubuntu and iptables without any front-end.
  • chovy
    chovy about 4 years
    How do I add this to /etc/iptables.rules? I get a syntax error when I add -I
  • BMitch
    BMitch about 4 years
    @chovy I can't see your screen from here.
  • chovy
    chovy about 4 years
    how do i add without iptables command in file?
  • chovy
    chovy about 4 years
    I'm using iptables-restore < rules. I want to know what to put in rules so the world cannot access my published ports. Only localhost and containers should be able to.
  • zukijuki
    zukijuki about 2 years
    Hi, thanks for the tips! btw, why do we still need a reverse proxy?
  • paaacman
    paaacman about 2 years
    We still need a reverse proxy because we want to expose the service through the reverse proxy, to a specific domain only or with allow / deny IP rules, for exemple.