James Thew - Fotolia
Get started with Docker Bench for Security
Common vulnerabilities in OSes and configuration files can plague Docker hosts. Learn how to set up Docker Bench for Security and use the open source tool to fortify hosts against threats.
If you've built and deployed Docker hosts, you know it can be a security nightmare. Docker Bench for Security is a free scanning and reporting tool designed to assist with common configuration issues and problems with libraries in the Docker host build.
This article covers what Docker Bench for Security does and how it works. Then, follow along with a tutorial to set up the security benchmarking tool. Finally, learn some common security vulnerabilities that Docker administrators introduce into the configuration, and how to avoid them. The more secure your build is, the better its Docker Bench for Security score will be.
What does Docker Bench for Security do?
Docker Bench for Security enables administrators to build a secure baseline in the Docker deployment process. This security scan tool should be used to harden golden host configurations, not on a per-VM basis. Piecemeal VM scans are more work than a baseline host security effort, and they also raise the chances of configurations being different across the environment.
Docker Bench for Security scans the Docker host for common configuration issues, such as loose settings in configuration files and system rights and questionable defaults. The tool relies on a database of Common Vulnerabilities and Exposures (CVE) to audit the libraries and executables on the system in question.
At the end of each scan, it provides a score. Admins can track a host configuration's Docker Bench for Security score to mark improvements over time.
How to set up Docker Bench for Security
This security tool comes as a Docker image to download by default. Alternatively, you can use the direct script download approach.
Deployment is pretty simple and straightforward. Use an Ubuntu 20.04 LTS VM, and follow a series of simple steps.
As a best practice, replace any existing version of Docker with the latest release from Docker. Log into the host and configure as required. Use SSH so that you can copy and paste these commands.
Prepare Docker. Set up a new VM with no additional package install options selected. Or, remove old versions of Docker. Use apt-remove to remove unneeded packages. Then, add the required files for Docker. There are a handful of install requirements that Docker depends on.
sudo apt install apt-transport-https ca-certificates curl software-properties-common -y
Install the new repository and signature. By default, Ubuntu doesn't trust unsigned repositories, so you need to import the keys and accept them. Download the key and install it with a one-line command:
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
When you follow this tutorial, don't miss the - at the end of the command.
To finish preparing for Docker Bench for Security, install the latest Docker release version. You can update the Docker version with this command:
sudo apt-get update && apt-get install docker-ce
By default, it should automatically start, although you might need to wait a few minutes for the system to update. To check the status of Docker, use sudo docker status as shown in Figure 1. If you see "Active: active" then your setup is good.
Install Docker Bench for Security. To get the tool working, use the docker run command, which should be familiar to most administrators:
docker run -it --net host --pid host --userns host --cap-add audit_control \ -e DOCKER_CONTENT_TRUST=$DOCKER_CONTENT_TRUST \ -v /etc:/etc:ro \ -v /usr/bin/containerd:/usr/bin/containerd:ro \ -v /usr/bin/runc:/usr/bin/runc:ro \ -v /usr/lib/systemd:/usr/lib/systemd:ro \ -v /var/lib:/var/lib:ro \ -v /var/run/docker.sock:/var/run/docker.sock:ro \ --label docker_bench_security \ docker/docker-bench-security
The text above is a single command. We use the \ to split it over several lines for ease of use. Once Docker Bench for Security downloads onto the system, it automatically runs, as specified in the command line issued to it.
This tutorial covers how to install Docker Bench for Security via the command line. Some administrators will find it easier to run the script version: Just download the script from GitHub and run it.
Docker Bench for Security output
When Docker Bench for Security runs a security audit, it generates a series of statements regarding common issues. An example of this output is shown in Figure 3. The red [WARN] denotes major issues. Yellow [NOTE] is a simple warning and the blue [INFO] is just advisory.
At the bottom of the output is a current score. The higher your Docker Bench for Security score, the more confidence you can have in the configuration, as highlighted in Figure 4. You can run these scripts as many times as you want to update your Docker security benchmark.
Notice how the output is broken down into headers and subheaders. Each header refers to a specific aspect of overall deployment security. Not all recommendations apply to all configurations. For example, if you only intend to run one host with no automation, you can ignore the Kubernetes section. Take the time to decipher the output, and don't blindly follow all the recommendations.
As you harden the hosts, these fixes should become part of the golden host configuration, rolled out whenever new hosts deploy. Update the tool often and run it against your development configuration, as CVE lists change frequently and configuration best practices evolve.
Common Docker configuration mistakes
There are typical configuration errors that affect Docker host security. Remediate them to get a better score out of Docker Bench for Security immediately. A lot of these fixes vary, but the concepts should apply to your specific case, as the intricacies of the configuration files don't change much.
OS partition. Docker images should be stored on a separate partition than the operating system. This is foundational -- it is check 1.1 on the Docker Bench for Security script -- but overlooked by many administrators.
By storing Docker images on a separate partition from the OS, administrators prevent a container instance from consuming all the space on the root partition. It is a best practice that can prevent many frustrations.
To find out where Docker stores all its images, run:
docker info | grep -I Root
On a new, empty standalone host, partition issues are simple to fix. Firstly -- and crucially -- stop the Docker service:
sudo service docker stop
Open or create the Docker daemon configuration file /etc/docker/daemon.json and add:
{ "data-root": "/test" }
Assuming the partition and folder are mounted and available, just restart the service. To check the changes have taken, rerun the docker info | grep -I Root command. The new change should display.
You can configure the partitions after the installation, but it's a best practice to set it up at installation time. Docker hosts are by nature highly dynamic, so all configuration changes should be built into the host deployment.
Configuration files. IT admins use the daemon.json Docker daemon configuration file to override defaults. The format is important for Docker administrators. While building the file, add and test one line at a time, restarting the Docker daemon as you go.
There are a few additional configuration entries that can negate some of those red [WARN] results from the security benchmark.
Add the following items:
- userns-remap. This entry essentially remaps the container ownership, relating to the namespace. It changes from root to a limited account: dockremap. That change ensures that no root-based escapes can occur.
- no-new-privileges. In a similar vein, the no-new-privileges entry prevents containers from acquiring any additional rights beyond those granted at startup time.
- icc. The icc entry is perhaps the simplest configuration change to make for Docker security. It stops the Docker daemon from automatically adding the Docker image to the default network.
Networking. By default, all the containers share the same networking configuration -- in essence, it is promiscuous mode. In this setup, traffic intended for a specific VM can be read by all. This setup is not ideal for security. For example, if hackers compromised a Docker container instance, they could see all the data flowing across the local host network.
To fix this, it is best practice to create a new network group -- a bridge network -- for each set of servers that need to communicate. This setup isolates networks, hardening the container deployment against exploitation.
To get a list of current networks, use the docker network ls command:
sudo docker network ls
That one bridge entry needs to be split out into additional bridges. You can then assign the containers to the appropriate bridge. The command is straightforward:
docker network create -d bridge new_net_bridge
Reissuing the docker network command will show the new bridge. Each bridge gets a new network range by default. To connect the bridge to the container, use another command:
docker network connect new_net_bridge currentcontainer
Once that is assigned, check the settings on the network:
docker network inspect new_net_bridge
At this point, containers on the same network should be able to talk to each other, but not to other containers.
Helpful grep
If you run the security scan script and have trouble keeping up with the [WARN] entries, try piping the docker-bench command through grep. This method displays just the warnings. Use these commands:
sudo ./docker-bench-security.sh | grep [WARN]
Auditing
Security audits are certainly useful after an attack, but they're even better to run before anything bad happens. For Docker, use auditd, one of the packages in the Ubuntu repository. This application will watch for changes to key files and report them.
Install auditd with apt install:
sudo apt install auditd -y
All the files to check are kept in /etc/audit/audit.rules. Add several additional items to check for better security:
-w /usr/bin/docker -p wa -w /usr/bin/dockerd -p wa -w /var/lib/docker -p wa -w /etc/docker -p wa -w /lib/systemd/system/docker.service -p wa -w /lib/systemd/system/docker.socket -p wa -w /etc/default/docker -p wa -w /etc/docker/daemon.json -p wa -w /usr/bin/docker-containerd -p wa -w /usr/bin/docker-runc -p w -w /usr/bin/containerd -p wa
Restart the auditd service and re-run the Docker Bench for Security scan. You should see the number of warnings fall dramatically.
No matter what you do, there's another best practice to follow. Always test changes before deploying to production.