Docker is a software application that allows you to design and deploy containerized applications and services. It is a Platform as a Service (PaaS) that uses the host OS Kernel rather than hypervisors like VirtualBox. Docker containers include the requirements and libraries required for an application to execute. As a result, containers eliminate the need to install dependencies manually. Because containers use the host kernel, they are becoming more efficient than virtual computers.
Docker containers have dominated the software engineering business. Containers are the dominating technology and can be installed anywhere. Because of its flexibility, the Docker container ecosystem has several security flaws.
Docker supports virtual network settings and, for its part, makes heavy use of iptables on Linux to establish network connectivity between containers, the host system, and distant computers. However, inspecting the host’s INPUT chain and filtering incoming traffic is insufficient to safeguard running containers.
As a network administrator, you may be familiar with adding a filter rule to your ruleset only to discover that it does not fulfill the intended purpose. Iptables is still the preferred packet filtering tool on Linux platforms. However, automatically inserted rules (such as those generated by the Docker daemon) invariably result in side effects in semi-automatically or manually generated rulesets. The primary security issue emerges when a rule is designed to filter incoming packets but is ignored when packets for Docker containers are detected.
Iptables and Docker
Iptables can be used to manage network traffic to and from a Docker container, controlling the flow of packets to specific ports and IP addresses. By setting up iptables rules correctly, you can prevent unauthorized access to the container and protect against malicious attacks.
Docker on Linux manipulates iptables rules to offer network isolation. While this is an implementation issue, you should not change the rules Docker adds to your iptables policies. It does have ramifications for what you need to do if you wish to have your own policy initiatives in addition to those maintained by Docker.
Suppose you run Docker on a host accessible through the Internet. In that case, you need to set up iptables policies to restrict unwanted access to containers or other services operating on your host. This page explains how to do so and what precautions you should take.
Chains and Tables
The basic structure of filter rules in iptables is straightforward. Filter, mangle, and NAT are the three most well-known tables. The filter table is primarily used to generate the packet filter rules. The mangle table allows you to explicitly change IP header information and label packets in the processor to recognize them in other rules when they transit through the iptables chains.
You specify rules in the NAT table to conduct address translation for packets during packet forwarding. For example, you may use the NAT table on your home router to transmit packets from your private network region to the Internet and reassign incoming packets to the relevant machines on your network.
The security and raw tables are significantly less often used, although they provide capabilities to prevent connection monitoring and label packets in SELinux environments.
Each of the five tables has its own rule chain, which is followed from top to bottom until a policy is applied to the validated package. Users can construct new chains in addition to predefined chains, primarily used to organize and order rules and simplify automated rule development and change.
At launch, the Docker daemon, required for Docker container virtualization, builds its own chains and rules. They are, however, merely the foundation for arranging the rules that are later constructed automatically in the absence of a functioning container.
Docker employs a virtualized network with its interface, commonly referred to as docker0. The Route chain contains rules that are used to forward packets on this interface to execute containers. Docker’s interface and containers utilize private IP addresses in the range 192.168.0.11/20.
To provide network access to the host system from the containers, matching rules with both source and destination NAT are added to each container’s NAT table. These principles make container communication possible in all directions and between containers. Suppose you construct a distinct network for your containers. In that case, Docker automatically generates a bridge interface for every one of these networks and then expands the filter rules with equivalent bridge interface rules.
Prioritize iptables policies above Docker rules
Docker installs two unique iptables chains named DOCKER and DOCKER-USER, which guarantees that all incoming packets are examined first by these chains.
The DOCKER chain now contains all of Docker’s iptables rules. Do not manually alter this chain. Add rules that load before Docker’s rules to the DOCKER-USER chain if necessary. These rules take precedence over any rules that Docker generates automatically.
Rules added to the FORWARD chain – whether manually or automatically by another iptables-based firewall – are reviewed after these chains. This implies that if you expose a port using Docker, it will be exposed regardless of the restrictions defined in your firewall. If you want those restrictions to apply even when a port is exposed via Docker, add them to the DOCKER-USER chain.
Restriction of Docker host connections
All external source IPs are permitted to connect to the Docker host by default. Insert a negated policy at the beginning of the DOCKER-USER filter chain to enable a specific IP or network to access the containers. The following rule, for example, bans dynamic routing from all IP addresses except 192.168.0.11:
sudo iptables -I DOCKER-USER -i ext_if ! -s 192.168.0.11 -j DROP
Please remember that ext_if must be changed to coincide with your host’s external interface. Instead, you might enable connections from a source subnet. The following rule restricts access to the 192.168.0.12/24 subnet:
sudo iptables -I DOCKER-USER -i ext_if ! -s 192.168.0.12/24 -j DROP
Note: If you run into unprecedented errors, please execute the command below to install docker on your Ubuntu OS:
sudo apt install docker.io
Finally, using –src-range, you may define a range of IP addresses to accept (also remember to include -m iprange when using –src-range or –dst-range):
sudo iptables -I DOCKER-USER -m iprange -i ext_if ! --src-range 192.168.1.1-192.168.0.3 -j DROP
To control both the source and destination, use -s or –src-range with -d or –dst-range. For example, if the Docker server listens on 192.168.1.1 and 192.168.0.3, you may create rules that only apply to 192.168.0.3 while leaving 192.168.1.1 accessible. iptables is difficult, and more complex rules are outside the scope of this topic.
Stop Docker from modifying iptables
The iptables key can be changed to false in the Docker engine’s configuration file at /etc/docker/daemon.json. However, this option is not suitable for most users. It is not feasible to prevent Docker from establishing iptables rules entirely, and creating them after the fact is exceedingly complicated and beyond the purview of these instructions. Setting iptables to false will almost certainly damage Docker engine container networking.
Docker automatically generates a firewalld zone called docker and integrates all network interfaces it establishes (for example, docker0) into the docker zone to provide smooth networking if you are running Docker version 20.10.0 or above with firewalld on your system and –iptables enabled.
To delete the docker interface from the zone, use the firewalld command below:
# Please substitute the correct zone and docker interface firewall-cmd --zone=trusted --remove-interface=docker0 --permanent firewall-cmd –reload
The interface is inserted into the docker zone when the docker daemon is restarted.
Setting the container’s default bind-address
The Docker daemon will disclose ports on the 0.0.0.0 address by default, i.e., any address on the host. You may use the –ip option to provide a different IP address if you wish to modify that behavior to only expose ports on an internal IP address. Setting –ip, on the other hand, changes the default; it does not limit services to that IP address.
We have protected our Docker environments by installing and configuring iptables. Unless we wish them to be, none of our Docker-published ports are open to the public. We used iptables to build a bespoke Docker firewall. Hopefully, this will become the expected behavior and be provided with Docker out of the box one day! Dare to fantasize. Security is difficult. If you found this guide helpful, let me know via the comments section below.