1

Is there any possible way to setup the host firewall to allow connections only for the network Docker containers uses?

Intro

The only way I was able to connect to a OS hosted MySQL instance from my new Docker containers was by opening to ports:

sudo ufw allow 3310

Inside the Docker container I am then able to connect using:

 (Docker container): mysql -u testuser -p -h 172.100.0.1 -P 3310

However this way the port is open to the internet as well, I would rather use SSH to connect using credentials.

NOTE: MySQL bind-address=0.0.0.0 is set

Information

  • On Host:

NOTE: Showing only applicable Docker network information - my containers use a custom named network (d-custom-network)

  ifconfig

  d-custom-network: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
    inet 172.100.0.1  netmask 255.255.0.0  broadcast 172.100.255.255
    inet6 fe80::42:b8ff:fe7f:c4bf  prefixlen 64  scopeid 0x20<link>
    ether 02:42:b8:7f:c4:bf  txqueuelen 0  (Ethernet)
    RX packets 473  bytes 34668 (34.6 KB)
    RX errors 0  dropped 0  overruns 0  frame 0
    TX packets 403  bytes 119797 (119.7 KB)
    TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

  docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
    inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
    inet6 fe80::42:13ff:fefc:301f  prefixlen 64  scopeid 0x20<link>
    ether 02:42:13:fc:30:1f  txqueuelen 0  (Ethernet)
    RX packets 28509  bytes 1593290 (1.5 MB)
    RX errors 0  dropped 0  overruns 0  frame 0
    TX packets 33351  bytes 173437123 (173.4 MB)
    TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
  • Inside container:

    ip addr
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
          inet 127.0.0.1/8 scope host lo
     valid_lft forever preferred_lft forever
    69: eth0@if70: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
        link/ether 02:42:ac:64:00:04 brd ff:ff:ff:ff:ff:ff link-netnsid 0
        inet 172.100.0.4/16 brd 172.100.255.255 scope global eth0
     valid_lft forever preferred_lft forever
    
  • Docker network information:

     docker network ls
    
     8a35ff6a0a88        bridge                            bridge              local
     572f80997782        magento2-network-frontend         bridge              local
     4590216456c0        host                              host                local
     a79a85d3a426        none                              null                local
    
  • Docker network inspect: Partial content:

     docker network inspect magento2-network-frontend
    
     [
         {
             "Name": "glo-magento2.3-network-frontend",
             "Id": "572f809977826942d1b582c17f2ac67f25f4221ddfe5a2f504ccb12a3aa6c786",
             "Created": "2020-08-11T12:05:51.988694032Z",
             "Scope": "local",
             "Driver": "bridge",
             "EnableIPv6": false,
             "IPAM": {
                 "Driver": "default",
                 "Options": null,
                 "Config": [
              {
                  "Subnet": "172.100.0.0/16"
              }
          ]
      },
    

Partial iptables listing (Docker destinations) - : I noticed these connection information when connecting from inside the container when trying to connect in MySQL testing with a failed login

   FROM Within container:

   ERROR 1045 (28000): Access denied for user 'testuser'@'cpe-172-100-0-4.twcny.res.rr.com'
   ping cpe-172-100-0-4.twcny.res.rr.com
   PING cpe-172-100-0-4.twcny.res.rr.com (172.100.0.4) 56(84) bytes of data.
   64 bytes from 54195d3486eb (172.100.0.4): icmp_seq=1 ttl=64 time=0.063 ms

   iptables -L 

   Chain DOCKER (2 references)
   target     prot opt source               destination
   ACCEPT     tcp  --  anywhere             cpe-172-100-0-2.twcny.res.rr.com  tcp dpt:6082
   ACCEPT     tcp  --  anywhere             cpe-172-100-0-2.twcny.res.rr.com  tcp dpt:6081
   ACCEPT     tcp  --  anywhere             cpe-172-100-0-3.twcny.res.rr.com  tcp dpt:6379
   ACCEPT     tcp  --  anywhere             cpe-172-100-0-4.twcny.res.rr.com  tcp dpt:http-alt
   ACCEPT     tcp  --  anywhere             cpe-172-100-0-5.twcny.res.rr.com  tcp dpt:https
   ACCEPT     tcp  --  anywhere             cpe-172-100-0-5.twcny.res.rr.com  tcp dpt:http

What I tried

I thought I would be able to use the method mentioned here : This is also why I investigated how to make sure the docker network name used by host (ie. ifconfig output), in my example I created d-custom-network

Direct link

To allow access on a specific port let’s say port 3360 only to specific network interface eth2, then you need to specify allow in on and the name of the network interface:

 $ sudo ufw allow in on eth2 to any port 3306

 $ sudo ufw reload

So I tried sudo ufw allow in on d-custom-network to any port 3310

That is when I noticed the docker cpe-172-100-0-2.twcny.res.rr.com output when trying to force a failed login for testing the location I connect from.

I do not think I understood the usage correctly, and assumed that I could use the internal network 172.100.0.* where my docker containers connect to/from.

How would I go about this?

CvRChameleon
  • 367
  • 1
  • 5
  • 29

1 Answers1

1

I had the same question, and the following worked for me (all commands run on the host):

  1. Identify which network your container is attached to:

    $ docker inspect mycontainer
    ...
        "Networks": {
            "bridge": {
                "IPAMConfig": null,
                "Links": null,
                "Aliases": null,
                "NetworkID": "b8ecee4683b22db9154f8c3e56b48f371b2bdf663f25d092112fc7eb410a4816",
                "EndpointID": "56cd2b50116f92d49c643457059a0ef0350e14509a16d1b615f806bb62eb4ad5",
                ...
            }
        }
    ...
    

    My container mycontainer is attached to the network named bridge:

    $ docker network ls
    NETWORK ID     NAME      DRIVER    SCOPE
    b8ecee4683b2   bridge    bridge    local
    f9a4ecf5db2b   host      host      local
    cc168ad8f868   none      null      local
    
  2. Identify which of the host's network interfaces corresponds to the bridge network:

     $ docker network inspect bridge
     ...
     "Options": {
         ...
         "com.docker.network.bridge.name": "docker0",
         ...
     },
     ...
    

    My network bridge corresponds to host network interface docker0:

     $ ip addr
     ...
     3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
         link/ether 02:42:c8:b4:a4:ba brd ff:ff:ff:ff:ff:ff
         inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
            valid_lft forever preferred_lft forever
         inet6 fe80::42:c8ff:feb4:a4ba/64 scope link 
            valid_lft forever preferred_lft forever
     ...
    
  3. Allow traffic from the identified host network interface docker0, to port 3310 anywhere:

    $ sudo ufw allow in on docker0 to any port 3310
    

I tested it, and the database port on the host is now:

  • accessible when connecting from inside the docker container, and
  • filtered by the firewall when trying to connect from the network outside the host.

Also, since we're talking about securing a docker host with UFW, I feel it's important to mention this side note/warning about using UFW with docker, in case you're not already aware: See this discussion for details, in summary, Docker by default may override UFW's firewall rules in ways that a typical user may not be expecting. In particular, I think that exposing a port on a container via docker -p actually punches a hole in your firewall on that port, which UFW does not see or control.

  • Thank you, when I get back to this part of Docker I will investigate this further. Can you please clarify `docker0` in your solution, how do I find/get this `docker0` to use as reference? Regarding Docker/ufw rules, I just seen those entries in `iptables` as shown in my example. I will investigate the link thanks! – CvRChameleon Mar 23 '21 at 07:23
  • Good question. When I first answered, I was not entirely sure myself, but I've now learned a bit more about Docker networking. Just edited my answer to try to show how I think the interface name should be precisely identified, to the best of my current understanding. – David Breese Apr 04 '21 at 17:56
  • 1
    Thanks David, I needed this information again because I created new custom containers that needed a MYSQL instance hosted on the `host` and connect from within `docker containers`. I also had a custom network `ip addr showed d-custom-network`. I wonder why my original attempt (question derived from originally) didn't work, because it seems I tried that last year. Useful to have references for issues that repeat over time. – CvRChameleon Apr 09 '21 at 09:42