Get Even More Visitors To Your Blog, Upgrade To A Business Listing >>

Limiting access to docker containers to dynamic IPs

Ports exposed by Docker containers are visible to the entire wide web by default. You may want to limit access to the services from whitelisted IP addresses. Docker documentation explains how to limit access to containers by IP address. But that would work only with static IP addresses.

What if you want to access the container services from a dynamic IP? You will need a script to automatically update the IP address, whenever it changes.

Since I am already using ConfigServer Security & Firewall (CSF), which allows whitelisting dynamic IP Addresses using Dynamic DNS, I decided to use the same list to whitelist Docker access too.

Steps

  1. Create a DDNS account with any service provider. I am using the free DDNS service from No-IP.com
  2. Add the new DDNS hostname to your DDNS list file specified by the  FILE_LIST_DDNS_HOST variable. If you are using the CSF DDNS list, skip this step and leave the variable empty.
    echo "newhost.no-ip.org" >> /etc/csf/csf.dyndns
  3. Add the static IP addresses you need to whitelist to the file specified by the FILE_LIST_STATIC_IP variable
    echo "w.x.y.z" >> /etc/csf/csf.allow
  4. Now we have to update the Iptables rules, whenever the IP changes. In order to detect IP address change, a md5 hash of the file was created. This way, we can detect the IP changes by monitoring the file hash. When the file content is modified, read the new IPs from the list, replace the current iptables rules with new IP address. To do this, create the file /usr/local/bin/ddns-docker and paste the following bash script into it
    #!/bin/bash
    
    # Docker interface name
    DOCKER_IFACE=docker0
    
    # List of static ip addresses to whitelist
    FILE_LIST_STATIC_IP=/etc/csf/csf.allow
    
    # List of DDNS hostnames to whitelist
    FILE_LIST_DDNS_HOST=/etc/csf/csf.dyndns
    
    # List of DDNS IP addresses
    # Required only for CSF integration mode.
    # The option is ignored when FILE_LIST_DDNS_HOST is set
    # FILE_LIST_DDNS_IP=/var/lib/csf/csf.tempdyn
    
    # Resolve dynamic dns hosts from file, if specified
    if [ ! -z "$FILE_LIST_DDNS_HOST" ]; then
     echo -n `date +"[%D %T]"` "Resolving DDNS hosts - "
     FILE_LIST_DDNS_IP="$FILE_LIST_DDNS_HOST.tempdyn"
     echo -n "" > $FILE_LIST_DDNS_IP
     
     sed -e 's/#.*$//' -e '/^$/d' $FILE_LIST_DDNS_HOST | while read HOST; do
     echo -n "$HOST, "
     getent hosts $HOST | awk '{ print $1 }' >> $FILE_LIST_DDNS_IP
     done
     echo -e "\b\b "
    fi
    
    if [ "$1" == "-f" ]; then
     UPDATE=1
    else
     md5sum --status -c "$FILE_LIST_DDNS_IP.md5"
     UPDATE=$?
    fi
    
    if [ $UPDATE -ne 0 ]; then
     if [ "$1" == "-f" ]; then
     echo `date +"[%D %T]"` "Forcefully updating Iptables rules"
     else
     echo `date +"[%D %T]"` "DDNS Updated"
     fi
     
     md5sum $FILE_LIST_DDNS_IP > "$FILE_LIST_DDNS_IP.md5"
     
     # Flush existing rules
     /sbin/iptables -F DYNDOCKER
     
     # Whitelist static IPs from the file, if specified
     if [ ! -z "$FILE_LIST_STATIC_IP" ] ; then
     echo -n `date +"[%D %T]"` "Whitelisting static IPs - "
     sed -e 's/#.*$//' -e '/^$/d' $FILE_LIST_STATIC_IP | while read IP; do
     echo -n "$IP, "
     /sbin/iptables -A DYNDOCKER -o $DOCKER_IFACE -s $IP -j DOCKER 
     done
     echo -e "\b\b "
     fi
     
     # Add new IPs
     echo -n `date +"[%D %T]"` "Whitelisting dynamic IPs - "
     cat $FILE_LIST_DDNS_IP | while read IP; do 
     echo -n "$IP, "
     /sbin/iptables -A DYNDOCKER -o $DOCKER_IFACE -s $IP -j DOCKER
     done
     echo -e "\b\b "
     
     # Allow RELATED/ESTABLISHED connections
     /sbin/iptables -A DYNDOCKER -o $DOCKER_IFACE -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
     # Allow connections from container to internet
     /sbin/iptables -A DYNDOCKER -i $DOCKER_IFACE ! -o $DOCKER_IFACE -j ACCEPT
     # Allow connections from container to container
     /sbin/iptables -A DYNDOCKER -i $DOCKER_IFACE -o $DOCKER_IFACE -j ACCEPT
    
     # Drop all other connections
     /sbin/iptables -A DYNDOCKER -o $DOCKER_IFACE -j DROP
    else
     echo `date +"[%D %T]"` "DDNS Up-to-date"
    fi
    

    Make the script executable

    chmod +x /usr/local/bin/ddns-docker

    Force update the iptables rules

    /usr/local/bin/ddns-docker -f

    Now create a root cron job to run the script every 2 minutes. Make sure that you are adding the job to root user, as the dynamic ip file created by CSF is readable only by root user.

    */2 * * * * /usr/local/bin/ddns-docker >> /var/log/ddns-docker/stdout.log 2>&1

    Create the log directory

    mkdir /var/log/ddns-docker/
  5. Now we need to redirect requests bound for the docker interface to the DYNDOCKER chain. For this, create a new file at /usr/local/bin/firewall-docker-fix with the following content
    #!/bin/sh
    
    DOCKER_IFACE=docker0
    
    # Create DYNDOCKER Chain
    /sbin/iptables -N DYNDOCKER
    
    # Redirect packets for docker interface to DYNDOCKER chain
    /sbin/iptables -I FORWARD -o $DOCKER_IFACE -j DYNDOCKER
    
    # Add additional IPs to whitelist
    # /sbin/iptables -I FORWARD -o $DOCKER_IFACE -s w.x.y.z -j DOCKER 
    
    # Update DDNS
    /usr/local/bin/ddns-docker -f
    

    You may add additional static IPs that you wish to whitelist to the above file

  6. Now create a systemd service to automatically call our script whenever docker restarts. Create the file /usr/lib/systemd/system/ddns-docker.service with the following content
    [Unit]
    Description=Fix Firewall after docker startup
    After=docker.service
    Requires=docker.service
    
    [Service]
    ExecStart=/usr/local/bin/firewall-docker-fix
    
    [Install]
    WantedBy=multi-user.target

    Enable the service

    sudo systemctl enable ddns-docker.service
  7. When CSF is restarted, it will flush all our iptables rules. To add the rules back after CSF restart, call the above script from the CSF pre iptables configuration hook script at /etc/csf/csfpre.sh
    echo "/usr/local/bin/firewall-docker-fix" >> /etc/csf/csfpre.sh

Update

I have modified the ddns-docker script to remove CSF dependency. Also, now you can whitelist static ip addresses, as an optional feature.

The files in this tutorial can be downloaded from https://github.com/JoyceBabu/ddns-docker



This post first appeared on Joyce Babu | Read, Learn And Share., please read the originial post: here

Share the post

Limiting access to docker containers to dynamic IPs

×

Subscribe to Joyce Babu | Read, Learn And Share.

Get updates delivered right to your inbox!

Thank you for your subscription

×