One of the postings on Hacker News that caught attention over the last couple of days was an email sent to the Docker security team that focused on a very outrageous security concern with Docker. Even if you expose the port to a loopback address with a parameter like -p 127.0.0.1:80:80, the service can still be accessed externally, what happened?

The reason for this is simple: Docker has added this Iptables rule.

1
2
3
4
🐳  → iptables -nvL DOCKER
Chain DOCKER (2 references)
 pkts bytes target prot opt in       out     source    destination
    0 0     ACCEPT tcp  --  !docker0 docker0 0.0.0.0/0 172.17.0.2  tcp dpt:80

As long as an external attacker sends traffic through this host to 172.17.0.2:80, it will match this rule and successfully access the services in the container; 127.0.0.1 doesn’t do much good.

The embarrassing thing is that users who choose to map the port to 127.0.0.1 basically feel so secure that they no longer want to take further security measures. Now comes the question, mapping to 127.0.0.1 can’t be said to be very secure, can it, only irrelevant to security.

Proof of Concept

Here is an example to verify it.

  1. Run a PostgreSQL container on machine A with port mapped to 127.0.0.1.

    1
    2
    
    # IP: 192.168.0.100
    🐳  → docker run -e POSTGRES_PASSWORD=password -p 127.0.0.1:5432:5432 postgres
    
  2. Machine B on the same LAN adds a routing table that directs all traffic accessing 172.16.0.0/12 to machine A.

    1
    2
    
    # IP: 192.168.0.200
    🐳  → ip route add 172.16.0.0/12 via 192.168.0.100
    
  3. Scan the port of machine A in machine B.

    1
    2
    3
    4
    5
    6
    7
    8
    
    
    🐳  → nmap -p5432 -Pn --open 172.16.0.0/12
    Starting Nmap 7.92 ( https://nmap.org ) at 2021-11-05 15:00 CDT
    Nmap scan report for 172.17.0.2
    Host is up (0.00047s latency).
    
    PORT     STATE SERVICE
    5432/tcp open  postgresql
    
  4. Connect directly to PostgreSQL in machine B.

    1
    2
    
    🐳  → psql -h 172.17.0.2 -U postgres
    Password for user postgres:
    

Solution

The fact that it’s not just 127.0.0.1, but that you map the container port to any address on the host, accessible externally, is outrageous!

The author of the email proposed a solution to the Docker team to optimize Docker’s iptables rules.

  1. First, strictly restrict the source addresses and network interfaces that are allowed to access the container ports

    For example, the original iptables rule for docker run -p 127.0.0.1:5432:5432 is as follows.

    1
    2
    3
    
    Chain DOCKER (2 references)
    pkts bytes target prot opt in       out     source    destination
        0 0     ACCEPT tcp  --  !docker0 docker0 0.0.0.0/0 172.17.0.2  tcp dpt:5432
    

    The improved iptables rules are as follows.

    1
    2
    3
    
    Chain DOCKER (2 references)
    pkts bytes target prot opt in out     source      destination
        0 0     ACCEPT tcp  --  lo docker0 127.0.0.1/8 172.17.0.2 tcp dpt:5432
    

    Similarly, if the address of the host is 192.168.0.100 and the mask is 24, then the iptables rule for docker run -p 192.168.0.100:5432:5432 should be as follows.

    1
    2
    3
    
    Chain DOCKER (2 references)
    pkts bytes target prot opt in   out     source         destination
        0 0     ACCEPT tcp  --  eth0 docker0 192.168.0.0/24 172.17.0.2 tcp dpt:5432
    
  2. Finally, the default behavior should be modified to map to 127.0.0.1 by default if no IP address is specified when using the -p parameter.

Although there are many people in the comments section have given the option of adding iptables rules to restrict, but this is unrealistic, there are thousands of users around the world are using the -p parameter to map the container port to 127.0.0.1, the attacker probably found this vulnerability long ago, we can not expect users to add iptables rules to restrict external access, the most reliable The most reliable way is to wait for Docker official to fix this bug and then upgrade it.