Skip to main content

Secure Docker Network

With iptables

 對於 Container 不同啟動方式,在 iptables 的腳本設計會有些不同。

    docker-compose: 透過橋接的網路介面(br-*) 與 DOCKER-USER 作限制。 docker: 透過 PRE_DOCKER 作限制。

    for docker-compose)

    #!/usr/bin/env bash
    
    # Purpose: Restrict the access to the container from external IPs.
    # Author: Alang, 2019/8/14
    #
    
    CONTAINER="nginx_mysql_web_1"
    EXT_IF="eth0"
    BRG_IF="br-7e7de5a4dfa6"  # If no br-XXXX, set it to docker0
    
    if [ ! -x /usr/bin/docker ]; then
        echo "Abort: Unable to run the docker command!"
        echo "Recommendation: Check if the Docker was installed."
        exit 1
    fi
    
    # Check the network interfaces
    for i in $EXT_IF $BRG_IF;do
        if ! (ip a show $i >/dev/null 2>&1); then
            echo "Abort: The network interface $i doesn't exist"
            exit 1
        fi
    done
    
    # Check if the DOCKER-USER chain exists, if it does flushing the rules.
    iptables -C FORWARD -j DOCKER-USER 2> /dev/null
    
    if [ $? -eq 0 ]; then
        # Flush all existing rules
        iptables -F DOCKER-USER
    else
        echo "Abort: The chain DOCKER-USER not found!"
        echo "Recommendation: "
        echo "  - Is the Docker daemon running?"
        echo "  - Is the version of Docker 17.06+?"
        exit 1
    fi
    
    ## Docker container named www-nginx public access policy
    ## If using docker-compose, change FORMAT to
    ## --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'
    ##
    #WWW_IP="$(/usr/bin/docker inspect --format {{.NetworkSettings.IPAddress}} $CONTAINER 2>/dev/null)"
    WWW_IP="$(/usr/bin/docker inspect --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $CONTAINER 2>/dev/null)"
    
    if [ -z "$WWW_IP" ];then
        echo "Abort: The docker IP isn't detected!"
        echo "Recommendation:"
        echo "  - Is the specified container UP?"
        echo "  - Adjsut the variable \$WWW_IP."
        exit 1
    fi
    
    # Default action
    iptables -I DOCKER-USER -i $EXT_IF -j DROP   
    
    ## Insert web server container filter rules  
    ## Allow All IPs to access 80 & 443
    #iptables -I DOCKER-USER -i $EXT_IF -p tcp -d $WWW_IP --dport 80  -j ACCEPT
    #iptables -I DOCKER-USER -i $EXT_IF -p tcp -d $WWW_IP --dport 443 -j ACCEPT
    ## Allow Cloudflare IPs to acces 443
    ## Check the IP list of Cloudflare at the URL https://www.cloudflare.com/ips-v4
    iptables -I DOCKER-USER -o $BRG_IF -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
    iptables -I DOCKER-USER -i $BRG_IF ! -o $BRG_IF -j ACCEPT
    iptables -I DOCKER-USER -m state --state RELATED -j ACCEPT
    iptables -I DOCKER-USER -i $BRG_IF -o $BRG_IF -j ACCEPT
    
    iptables -I DOCKER-USER -i $EXT_IF -p tcp  -d $WWW_IP -s 173.245.48.0/20  --dport 443 -j ACCEPT
    iptables -I DOCKER-USER -i $EXT_IF -p tcp  -d $WWW_IP -s 103.21.244.0/22  --dport 443 -j ACCEPT
    iptables -I DOCKER-USER -i $EXT_IF -p tcp  -d $WWW_IP -s 103.22.200.0/22  --dport 443 -j ACCEPT
    iptables -I DOCKER-USER -i $EXT_IF -p tcp  -d $WWW_IP -s 103.31.4.0/22    --dport 443 -j ACCEPT
    iptables -I DOCKER-USER -i $EXT_IF -p tcp  -d $WWW_IP -s 141.101.64.0/18  --dport 443 -j ACCEPT
    iptables -I DOCKER-USER -i $EXT_IF -p tcp  -d $WWW_IP -s 108.162.192.0/18 --dport 443 -j ACCEPT
    iptables -I DOCKER-USER -i $EXT_IF -p tcp  -d $WWW_IP -s 190.93.240.0/20  --dport 443 -j ACCEPT
    iptables -I DOCKER-USER -i $EXT_IF -p tcp  -d $WWW_IP -s 188.114.96.0/20  --dport 443 -j ACCEPT
    iptables -I DOCKER-USER -i $EXT_IF -p tcp  -d $WWW_IP -s 197.234.240.0/22 --dport 443 -j ACCEPT
    iptables -I DOCKER-USER -i $EXT_IF -p tcp  -d $WWW_IP -s 198.41.128.0/17  --dport 443 -j ACCEPT
    iptables -I DOCKER-USER -i $EXT_IF -p tcp  -d $WWW_IP -s 162.158.0.0/15   --dport 443 -j ACCEPT
    iptables -I DOCKER-USER -i $EXT_IF -p tcp  -d $WWW_IP -s 104.16.0.0/12    --dport 443 -j ACCEPT
    iptables -I DOCKER-USER -i $EXT_IF -p tcp  -d $WWW_IP -s 172.64.0.0/13    --dport 443 -j ACCEPT
    iptables -I DOCKER-USER -i $EXT_IF -p tcp  -d $WWW_IP -s 131.0.72.0/22    --dport 443 -j ACCEPT
    
    # My IPs
    #iptables -I DOCKER-USER -i $EXT_IF -p tcp  -d $WWW_IP -s 219.70.88.133    --dport 443 -j ACCEPT
    
    
    [ $? -eq 0 ] && echo "Done."
    ## EOL

    for docker)

    #!/usr/bin/env bash
    
    # Usage:
    # timeout 10 docker_iptables.sh
    #
    # Use the builtin shell timeout utility to prevent infinite loop (see below)
    
    CONTAINER="raida17"
    
    if [ ! -x /usr/bin/docker ]; then
        exit
    fi
    
    # Check if the PRE_DOCKER chain exists, if it does there's an existing reference to it.
    iptables -C FORWARD -o docker0 -j PRE_DOCKER 2> /dev/null
    
    if [ $? -eq 0 ]; then
        # Remove reference (will be re-added again later in this script)
        iptables -D FORWARD -o docker0 -j PRE_DOCKER
        # Flush all existing rules
        iptables -F PRE_DOCKER
    else
        # Create the PRE_DOCKER chain
        iptables -N PRE_DOCKER
    fi
    
    # Default action
    iptables -I PRE_DOCKER -j DROP
    
    # Docker Containers Public Admin access (insert your IPs here)
    #iptables -I PRE_DOCKER -i eth0 -s 192.184.41.144 -j ACCEPT
    #iptables -I PRE_DOCKER -i eth0 -s 120.29.76.14 -j ACCEPT
    
    # Docker Containers Restricted LAN Access (insert your LAN IP range or multiple IPs here)
    #iptables -I PRE_DOCKER -i eth1 -s 192.168.1.101 -j ACCEPT
    #iptables -I PRE_DOCKER -i eth1 -s 192.168.1.102 -j ACCEPT
    
    # Docker internal use
    iptables -I PRE_DOCKER -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
    iptables -I PRE_DOCKER -i docker0 ! -o docker0 -j ACCEPT
    iptables -I PRE_DOCKER -m state --state RELATED -j ACCEPT
    iptables -I PRE_DOCKER -i docker0 -o docker0 -j ACCEPT
    
    # Docker container named www-nginx public access policy
    # If using docker-compose, change format to
    # --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'
    WWW_IP_CMD="/usr/bin/docker inspect --format {{.NetworkSettings.IPAddress}} $CONTAINER"
    WWW_IP=$($WWW_IP_CMD)
    
    # Double check, wait for docker socket (upstart docker.conf already does this)
    while [ ! -e "/var/run/docker.sock" ]; do echo "Waiting for /var/run/docker.sock..."; sleep 1; done
    
    # Wait for docker web server container IP
    while [ -z "$WWW_IP" ]; do echo "Waiting for $CONTAINER IP..."; WWW_IP=$($WWW_IP_CMD); done
    
    ## Insert web server container filter rules
    ## Allow All IPs to access 80 & 443
    #iptables -I PRE_DOCKER -i eth0 -p tcp -d $WWW_IP --dport 80  -j ACCEPT
    #iptables -I PRE_DOCKER -i eth0 -p tcp -d $WWW_IP --dport 443 -j ACCEPT
    ## Allow Cloudflare IPs to acces 443
    iptables -I PRE_DOCKER -i eth0 -p tcp -d $WWW_IP -s 103.21.244.0/22 --dport 443 -j ACCEPT
    iptables -I PRE_DOCKER -i eth0 -p tcp -d $WWW_IP -s 103.22.200.0/22 --dport 443 -j ACCEPT
    iptables -I PRE_DOCKER -i eth0 -p tcp -d $WWW_IP -s 103.31.4.0/22 --dport 443 -j ACCEPT
    iptables -I PRE_DOCKER -i eth0 -p tcp -d $WWW_IP -s 104.16.0.0/12 --dport 443 -j ACCEPT
    iptables -I PRE_DOCKER -i eth0 -p tcp -d $WWW_IP -s 108.162.192.0/18 --dport 443 -j ACCEPT
    iptables -I PRE_DOCKER -i eth0 -p tcp -d $WWW_IP -s 131.0.72.0/22 --dport 443 -j ACCEPT
    iptables -I PRE_DOCKER -i eth0 -p tcp -d $WWW_IP -s 141.101.64.0/18 --dport 443 -j ACCEPT
    iptables -I PRE_DOCKER -i eth0 -p tcp -d $WWW_IP -s 162.158.0.0/15 --dport 443 -j ACCEPT
    iptables -I PRE_DOCKER -i eth0 -p tcp -d $WWW_IP -s 172.64.0.0/13 --dport 443 -j ACCEPT
    iptables -I PRE_DOCKER -i eth0 -p tcp -d $WWW_IP -s 173.245.48.0/20 --dport 443 -j ACCEPT
    iptables -I PRE_DOCKER -i eth0 -p tcp -d $WWW_IP -s 188.114.96.0/20 --dport 443 -j ACCEPT
    iptables -I PRE_DOCKER -i eth0 -p tcp -d $WWW_IP -s 190.93.240.0/20 --dport 443 -j ACCEPT
    iptables -I PRE_DOCKER -i eth0 -p tcp -d $WWW_IP -s 197.234.240.0/22 --dport 443 -j ACCEPT
    iptables -I PRE_DOCKER -i eth0 -p tcp -d $WWW_IP -s 198.41.128.0/17 --dport 443 -j ACCEPT
    iptables -I PRE_DOCKER -i eth0 -p tcp -d $WWW_IP -s 199.27.128.0/21 --dport 443 -j ACCEPT
    
    
    # Finally insert the PRE_DOCKER table before the DOCKER table in the FORWARD chain.
    iptables -I FORWARD -o docker0 -j PRE_DOCKER