Docker’s massive adoption rates in recent years have made container security a critical consideration for organizations that use containers for development or production. Given that containers are more complex in many respects than virtual machines and other deployment technologies that were widely used before Docker, learning how to secure Docker containers can be complex as well.
In this article, we offer an overview of Docker container security. We explain why securing Docker containers is challenging, which default settings in a Docker environment you should change in order to make your containers more secure, and which best practices to follow when monitoring your containers for security.
Before Docker, most organizations used virtual machines or bare-metal servers to host applications. From a security perspective, these technologies are relatively simple. You need to focus on just two layers (the host environment and the application) when hardening your deployment and monitoring for security-relevant events. You also typically do not need to worry much about APIs, overlay networks or complex software-defined storage configurations, because these are not usually a major part of virtual-machine or bare-metal deployments.
Docker container security is more complicated, largely because a typical Docker environment has many more moving parts. Those parts include:
Your containers. You probably have multiple Docker container images, each hosting individual microservices. You probably also have multiple instances of each image running at a given time. Each of those images and instances needs to be secured and monitored separately.
The Docker daemon, which needs to be secured to keep the containers it hosts safe.
The host server, which could be bare metal or a virtual machine.
If you host your containers in the cloud using a service like ECS, that is another layer to secure.
Overlay networks and APIs that facilitate communication between containers.
Data volumes or other storage systems that exist externally from your containers.
So, if you feel like learning how to secure Docker containers is tough, don’t blame yourself. Docker security truly is more complicated than other security strategies.
Fortunately, that challenge can be overcome. While this article doesn’t profess to be an exhaustive guide to Docker security (for that, you should refer to the official Docker documentation), following are some best practices that can help you.
One handy thing that Docker makes easy to do is to configure resource quotas on a per-container basis. Resource quotas allow you to limit the amount of memory and CPU resources that a container can consume.
This feature is useful for several reasons. It can help to keep your Docker environment efficient and prevent one container or application from hogging system resources. But it also enhances security by preventing a compromised container from consuming a large amount of resources in order to disrupt service or perform malicious activities.
Resource quotas are easy to set using command-line flags. For full details, see the Docker documentation.
We’ve all been there: You are tired and you don’t want to fight with permission settings in order to get an application to work properly, so you just run it as root so that you don’t have to worry about permission restrictions.
That might be OK to do in a Docker testing environment if you’re learning how to use Docker for the first time, but in production, there is almost never a good reason to let a Docker container run with root permissions.
This is an easy Docker security best practice to follow because Docker doesn’t run containers as root by default. So, typically, there is nothing you have to change in a default configuration to prevent running as root. You do, however, have to resist the temptation to let a container run as root simply because it’s more convenient in some situations.
For added Docker security, if you use Kubernetes to orchestrate your containers, you can explicitly prevent containers from starting as root (even if an admin attempts to start one that way manually) using the MustRunAsNonRoot directive in a pod security policy.
Container registries are part of the reason Docker is so powerful. They make it easy to set up a central repository from which you can download container images with a few keystrokes.
However, the ease and convenience of container registries can become a security risk if you fail to evaluate the security context of the registry you’re using. Ideally, you’ll use a registry such as Docker Trusted Registry that can be installed behind your own firewall in order to mitigate the risk of breaches from the Internet.
And even if the registry is accessible only from behind the firewall, you should also resist the temptation to let anyone upload or download images from your registry at will. Instead, use role-based access control to define explicitly who can access what, and blacklist access from everyone else. Although it can be tempting to leave your registry accessible by anyone in order to simplify access and avoid having to configure new roles when someone new needs access, this inconvenience is worth it if it prevents a breach in your registry.
Speaking of registries, you should also be sure that the container images you pull come from a trusted source. This may seem overly obvious, but given that there are so many publicly available container images that can be downloaded quickly, it can be easy to pull an image accidentally from a source that is not verified or trusted.
For this reason, you should consider blacklisting public container registries other than official trusted repositories, such as those on Docker Hub.
You can also take advantage of image scanning tools to help identify some known vulnerabilities within Docker images. Most enterprise-level container registries have built-in scanning tools. Some of them, like Clair, can be used separately from a registry to scan individual images, too.
Also on the topic of where your container images come from — keep in mind that Docker images typically contain a mixture of original code and packages from upstream sources. Thus, even if the specific image you download comes from a trusted registry, the image could incorporate packages from other sources that may not be trusted. To make matters even more complicated, those packages could themselves be composed of code drawn from multiple sources, including third-party open source repositories, although the origins of the code may not always be clear from looking at the package itself.
In this context, source code analysis tools are useful. By downloading the sources of all packages in your Docker images and scanning them to identify where the code originated, you can determine whether any of the code incorporated into your container images contains known security vulnerabilities. (As an added benefit, source code analysis also helps you remain compliant with licensing requirements involving third-party code, which could affect you even if the packages you use don’t mention other licenses.)
As noted above, Docker containers typically rely heavily on APIs and networks to communicate with each other. That’s why it’s essential to make sure that your APIs and network architectures are designed securely, and that you monitor the APIs and network activity for anomalies that could indicate an intrusion.
Since APIs and networks are not a part of Docker itself, but are instead resources that you use in conjunction with Docker, steps for securing APIs and networks are beyond the scope of this article. However, the core message here is that API and network security are particularly important when you use Docker, so they shouldn’t be neglected.
Docker is a complicated beast, and there is no simple trick you can use to maintain Docker container security. Instead, you have to think holistically about ways to secure your Docker containers, and harden your container environment at multiple levels. Doing so is the only way to ensure that you can reap all the benefits of Docker containers without leaving yourself at risk of major security problems.