Working with docker stack and iptables

After moving to new country, I am setting up my home network to bring some of containers back from the cloud to self hosting from home. But the problem with my new router is there is no port based routing either all or none by setting the self hosting server as default DMZ server will route all the traffic to my server. So I should be very careful with the firewall setup.

As a preference I want to directly manage iptables instead of using the UFW (Uncomplicated Firewall) comes with the debian OS. But the problem from while using the docker stack /swarm deployment is it also directly updates the iptables. Docker will update firewall to open the ports which you have exposed to host while deploying the docker stacks.

After doing many research for some days I have come up with the following solution to achieve desired outcome. So I thought sharing step by step instructions will give some guidance for anyone trying to achieve the same thing.

Removing UFW package

sudo ufw disable
sudo apt-get remove ufw
sudo apt-get purge ufw

Purging the existing rules in iptables

sudo iptables -F
sudo reboot

After you have restarted you will view the iptables entries using the command below.

sudo iptables -L -n

By default iptables will have 3 Chains named INPUT, FORWARD and OUTPUT. You can rules in each chain using below command

sudo iptables -A INPUT -s 192.168.0.0/20 -p tcp -j ACCEPT

Here -A is used to indicate to append the rule and the chain name INPUT is used. Instead of -A we can use -I to insert the rule if no line number given or can pass –line-number <number> to insert rules at certain place. The rules are executed from top to bottom and the first matching rule action is taken. -j can have values ACCEPT or DROP or REJECT. DROP and REJECT behaves more like same where on REJECT the response is send to client and in case DROP no response send so client will wait for response and then will timeout.

Also if no matching rule is found in the given chain the default policy against the chain is used. By default we use policy as ACCEPT then create matching rules to set default behavior. If you are accessing the server over SSH connection please be mindful before creating reject policy as if there is no matching rule to accept your SSH connection your terminal will disconnect and you will be unable to access the server. By default the ip rules modified is not persisted on restart so you can gain your access through restart. There is a package which support persisting the rules when ever it changed but can be used once the setting is finalized to avoid loosing the connection to the server.

Also there are commands to manually save and restore the rules such as iptables-save and iptables-restore. You can learn more about using the help on the commands as in this post we will only cover how to use docker stack deployment with iptables.

Configuring the iptables

Add a rule to allow the connections from your internal network using below command.

sudo iptables -I INPUT -s 192.168.0.0/24 -j ACCEPT

Adding this as the first rule to make sure I am allowed to SSH and access all the ports from the internal network. You can restrict the ports if any one else using your internal network.

Now add the second rule to block access to others in the input chain.

sudo iptables -A INPUT -j DROP

In the second rule we have not included any source, so anything not matched by first rule will be matched but this. So all the ports will be blocked for external network in the INPUT chain.

Run a docker swarm / stack deployment in the server and expose some port such as port 80. Try to access it from a browser in local network. Surprisingly it won’t work even though the traffic from local network is allowed by iptables rules. This is where this gets interesting even though the traffic comes from local network then it is redirected and proxies through the network created by docker. Use the ip -a command to see all the network in your server as shown below.

So you also need to allow traffic in those networks in order to access the containers running in the server. Please add rules as shown below.

sudo iptables -I INPUT --line-number 2 -s 172.18.0.1/16 -j ACCEPT
sudo iptables -I INPUT --line-number 3 -s 172.17.0.1/16 -j ACCEPT

Now if you see the iptables using iptables -L -n command you should see something similar to below.

Now if you try to access the website running on a port from internal network will be accessible from any system running in local network. Docker will modify the rules in DOCKER-INGRESS chain will not directly impact your rules as your rules are added as first ones in the INPUT chain. Now you can add the rules in the INPUT chain before last (REJECT) line to allow certain port from outside the local network.

Hope this helped with your local network setup. Post your questions below in comments and I will response promptly and can update this post to reflect if any missing info.

Have a nice hosting.

Nish

Full stack developer, and Pega Certified Lead System architect since 2013 and with nearly 16 years experience in Pega. Connect with me in Linked in at https://www.linkedin.com/in/msnish/

Leave a Reply

Your email address will not be published. Required fields are marked *