Docker lets software developers and DevOps engineers rapidly package applications for production. Docker containers operate largely independently of their host but aren’t impervious to security threats. Here’s how to audit your Docker Engine installation to ensure maximum security for your host and your workloads.

Understanding Docker’s Architecture

The first step to assessing Docker risks is to understand how the technology actually works. Docker’s powered by three distinct components:

  • Docker Engine daemon – The background service which manages behind-the-scenes operations with containers and images.
  • REST API – Docker Engine provides a REST API which sends commands to the Docker daemon. The API is usually provided over a REST socket but may also be exposed over HTTP.
  • Docker command-line client – The Docker CLI runs when you use docker in a terminal. It sends commands to the Docker daemon. Commands are processed to determine the action to take.

An attacker compromising any of these components could gain access to your environment. Through proper configuration, you can protect your workloads and increase security compared to running applications directly on the host.

The Attack Surface

The Docker daemon presents the largest attack surface. Gaining control of the daemon provides access to the host and all your containers. The daemon usually runs as root, so a successful infiltration can grant unrestricted access to your physical machine.

You should ensure the Docker daemon socket (/var/run/docker.sock) is not accessible to anyone other than the root user. As the daemon can access the host, providing access to the socket effectively hands off control of your machine.

Docker’s daemon supports a TCP socket that enables remote control over the network. If you enable this feature, unencrypted communication will be offered without any authentication.

Avoid using TCP connections unless you’re in a network environment which you’ve specifically configured to be safe. You should set up TLS and ensure only authorised clients are allowed to connect.

Some Docker images may require you to mount the Docker socket into the container. This is often used by Docker management tools that provide an interface to containers running on your host. By mounting the socket in this way, anything inside the container could gain control of your system. Containers should never receive a Docker socket unless you’re sure the workload requires one.

Rootless Mode

Docker now supports a rootless mode which lets you run Docker without root access. This helps to improve security but comes with additional complexity at setup time.

Using rootless mode runs Docker and your containers inside a user namespace. Most Docker features will work, although there are some limitations.

Not every storage driver is available, overlay networks are unsupported and container networks are fully namespaced. This means you can’t directly access container IPs from the host without first entering the dedicated networking namespace.

Using rootless mode can be helpful in high-security environments where the integrity of the host is paramount. It helps lessen the impact of a successful attack by restricting opportunities to tamper with the wider system.

REST API Security

The Docker REST API is usually accessed via a UNIX socket. Permission checks are made using standard UNIX mechanisms.

You can expose the API over a TCP socket, enabling access via HTTP. This raises the risk of compromise. You should make sure your network access controls are set so traffic can only originate from approved hosts.

You should audit your firewall policies so you don’t overlook a device which could interact with the Docker API. Remember that limiting connections to localhost isn’t sufficient – this would still permit access from within Docker containers running on your machine, potentially enabling unintended privilege escalation.

Limiting Communication Between Containers

Docker allows all containers to communicate with each other over the default docker0 bridged network. A compromised container could snoop around this network to learn about its environment. It could use the bridge network as a vantage point to begin a wider infiltration of your workloads.

Disabling inter-container communication improves your security posture by enhancing container isolation. You’ll need to explicitly link containers together using the --link=ContainerName flag or your own Docker network.

Run Docker daemon with the --icc=false flag to disable communication over the docker0 bridge.

Restrict Conainer Capabilities

Linux kernel capabilities define the actions available to users with root access. Capabilities help to lockdown processes which are running as root, such as Docker containers. Each process should be given the minimum set of capabilities it needs.

Docker automatically runs containers with a limited selection of capabilities. Even this list is often excessive for a simple workload such as a web server. You can restrict it further by specifying your own list of capabilities available to a container.

docker run --cap-drop all --cap-add SYSLOG example-image:latest

The above command will run a container with only the SYSLOG capability. The --cap-drop flag disregards the default capability list. Capabilities are then added back with --cap-add, creating a whitelist.

It’s worth assessing your container against the kernel capability list. Drop any unused capabilities from containers running in production. This helps limit the damage a compromised container can cause.

Enable Built-In Kernel Features

Don’t disregard the security features built-in to your kernel. Docker works with existing technologies such as AppArmor and SELinux.

Some distributions, such as RedHat Linux, come with predefined SELinux system policies that augment Docker’s security. You can manually add SELinux support by running the Docker daemon with the --selinux-enabled flag. This activates a Docker policy to set SELinux labels on your containers. SELinux provides better isolation of container processes from host processes, improving your security posture.

The Basics

It’s easy to fixate on the complicated aspects of Docker security: rootless mode, daemon access and container communications. Don’t overlook the basics though – standard security practice still applies.

Always keep Docker Engine updated so you’ve got the latest bug fixes. You should also ensure your host’s kernel is fully patched. As containers share the same kernel as your host, any vulnerabilities could be exploited by your containerised applications.

It’s good practice to dedicate a specific physical machine or VM to running Docker. Don’t run any other services directly on the host. You can run them as containers instead, lessening the impact of a successful host compromise.

When configured correctly, Docker increases security by isolating applications. Taking the time to assess your position helps you identify potential risks and understand how attacks could begin. Locking down container privileges, protecting the Docker daemon and keeping your host updated will help you harden your containers.

Profile Photo for James Walker James Walker
James Walker is a contributor to How-To Geek DevOps. He is the founder of Heron Web, a UK-based digital agency providing bespoke software development services to SMEs. He has experience managing complete end-to-end web development workflows, using technologies including Linux, GitLab, Docker, and Kubernetes.
Read Full Bio »