Recently I needed to limit access to my docker containers to specific IP addresses. I did some searching and found some promising tutorials on using iptables with docker. However, none really brought me to a workable solution. The Docker documentation has a short article about using iptables however it is very limited. With the information I gathered from all of these sources I was about to come up with an easy to implement (and manage) solution. In this tutorial I will show you how I used ipset and iptables rules to limit docker container access to certain IP addresses (whitelist). Obviously, it can also have the reverse effect of blocking specific IP addresses (blacklist) from accessing your docker containers.

If you are unfamiliar with ipset, read "Create iptables rules based on hostname using ipset". It will give you the basic information you need to get started.

This was tested on Fedora 35 but should work on any Linux distro with minor tweaks.

Creating an IPSet

First we are going to create an ipset that will hold the list of IP addresses we want to allow access to our Docker containers.

[savona@fenrir ~]$ sudo ipset create docker-allowed hash:ip

The above command creates an empty ipset called docker-allowed. You can name it whatever you like. This will act as a container of sorts to hold the list of IP Addresses we want to act on.

Let's fill the ipset with a list of IP addresses. In the following example we are adding three IP addresses from my local network (10.0.0.0/24).

[savona@fenrir ~]$ sudo ipset add docker-allowed 10.0.0.2
[savona@fenrir ~]$ sudo ipset add docker-allowed 10.0.0.226
[savona@fenrir ~]$ sudo ipset add docker-allowed 10.0.0.227

Now we can list our ipset to ensure we have the expected configuration.

[savona@fenrir ~]$ sudo ipset list docker-allowed
Name: docker-allowed
Type: hash:ip
Revision: 5
Header: family inet hashsize 1024 maxelem 65536 bucketsize 12 initval 0x8a79bcd9
Size in memory: 320
References: 0
Number of entries: 3
Members:
10.0.0.227
10.0.0.226
10.0.0.2

Once you are happy with your ipset configuration you need to save it using the ipset save command. If you do not include this step, the ipset you created will be lost on reboot. In order to make the ipset rules persistent we need to save it to a configuration file.

sudo ipset save > /etc/ipset/ipset

NOTE: The location of the ipset file may be different on different distros. For example, my Red Hat 8 system saves it in /etc/sysconfig/ipset.

Now we have to ensure the ipset service is started and enabled.

sudo systemctl start ipset.service; sudo systemctl enable ipset.service

NOTE: For Fedora 35 I needed to install both ipset and ipset-service packages.

Now that we have out ipset created, we can use it to write IP tables rules that will affect all of the IP addresses in the set.

IPTables Rules to Permit Access to Docker Containers

According to the Docker documentation, manually created rules belong in the DOCKER-USER chain. These rules are applied to traffic before the rules in the DOCKER chain. The flow of iptables is outside the scope of this tutorial, but if you need more information comment below.

Let's create our first rule.

sudo iptables -I DOCKER-USER -i eth0 -m set ! --match-set docker-allowed src -j DROP

The above command will add a rule to the DOCKER-USER chain that will drop incoming packets on interface eth0, that do NOT match IP addresses in the docker-allowed set.

NOTE: You need to make sure you change eth0 to the name of your network interface.

This command can easily be used to block specific IP addresses as well. If you remove the ! then anything matching the docker-allowed ipset will be dropped. Effectively creating a blacklist.

For more information on iptables read "The Basics of IPTables".

Now we want to add one more rule. This rule will allow traffic that is part of a connection that is already established.

sudo iptables -I DOCKER-USER -i eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT

Conclusion

I tried several different methods to limit docker container access to certain IP addresses. This seemed to be the easiest and works well for my needs. It can also be easily modified to meet different requirements. If you know or use a different method I would love to hear about it in the comments.

Links and Resources