Hardening Docker Quick Tips

Marcin Teodorczyk
May 29 · 4 min read

It’s been over 6 years from the initial release of Docker on March 13, 2013. In the world of software development it looks more like a few centuries passed. Now, docker is widely regarded as mature and it is well working in many production environments. Also it has reasonably well functioning security controls enabled by default, namely namespaces, capabilities, cgroups. Nonetheless, due to the unavoidable differences in environments, it is not possible to make the best security configuration for everyone as a default.

If you want to take the security of your environment to the higher level, you can tweak controls that are already used by docker as well as add new ones. To make it easier to grasp one can split controls into two categories, namely related to docker host and related to docker images/containers.

Host

Briefly speaking, everything which comes with OS hardening topic should be considered here.

  1. We should have a minimal system, meaning no unnecessary software, services, users etc.
  2. The system should be up to date, at least when it comes to security patches.
  3. Services should be up to date. Particularly the docker daemon should be updated (some examples of serious vulnerabilities of docker from the last 2 years are CVE-2019–5736, CVE-2018–11757, CVE-2018–11756, CVE-2018–9862, CVE-2018–8115).
  4. Additionally we might choose to harden OS and basic services. For example enforce thoughtful policy on passwords, for SSH access maybe avoid passwords at all allowing users to only use cryptographic keys (disabling root login by the way) or limit docker daemon’s privileges and access to resources (more on that in the next part of the article).
  5. Finally we can use some security extensions such as SELinux, Seccomp, AppArmor, GRSecurity or others. Most of those will require a lot of additional effort though.

Docker Daemon, Images and Containers

In general, for docker images and containers the same principles as with host hardening apply. From the hardening perspective, the image can be viewed as an OS with one or more services (a proper image should include only one service and the software that is required by the service). The new thing here is the separation layer between the container and the docker host.

Non-Root

When building images it is worthwhile to create a low privilege user and then use it when running the container. We can do this adding following lines in Dockerfile:

RUN adduser -D limited_user
USER limited_user

The first one adds user named limited_user, the second one instructs docker to use this user inside the container. Apart from that we can specify the user when starting the container, like this:

docker run -u limited_user ubuntu

Of course the user specified in such way has to exist inside the container.

On a default centos host installation when running centos container with docker we get following output:

[root@localhost ~]# docker run -it centos /bin/bash
[root@58428c062898 /]# id
uid=0(root) gid=0(root) groups=0(root)

But when running with -u and user nobody (present inside the default centos image that is used), we see following:

[root@localhost ~]# docker run -u nobody -it centos /bin/bash
bash-4.2$ id
uid=99(nobody) gid=99(nobody) groups=99(nobody)

Limit Resources

Docker allows to limit resource availability per container. To allow the container to use no more than 1 CPU and 512MB of memory we use following:

docker run -it — cpus 1 — memory 512Mb centos

Docker Content Trust

When building images it is safer to use a trusted base OS and add needed software oneself than to get a ready to go image prepared by someone else, unless it is trustworthy. To ensure that we’re pulling the image that we think we’re pulling, we might use Docker Content Trust.

Check

When we have above low hanging fruits covered we can go further. A great place to start is docker-bench-security — an open source project that checks for dozens of common best-practices around deploying Docker containers in production. When run on default centos 7 installation gives the following output:

docker-bench-security run on default centos7 installation

Summary

Docker is a great solution providing an additional layer of separation and increasing manageability in complex systems. Basic hardening of a default installation can be done within few minutes — don’t run as root and appropriately limit resources available to containers. If you want to address wider range of issues — try docker-bench-security.

intive Developers

At intive we’re building great digital products for our customers. Day by day. We want to share with you our way of doing things, the challenges we face, the tricks and shortcuts we discover. A little peek behind the scenes — welcome to our intive_dev blog!

Marcin Teodorczyk

Written by

intive Developers

At intive we’re building great digital products for our customers. Day by day. We want to share with you our way of doing things, the challenges we face, the tricks and shortcuts we discover. A little peek behind the scenes — welcome to our intive_dev blog!