You are using Docker for development and testing purposes but did not yet take the step to use it in production? Then read on, because in this blog post we will take a look at how you can ensure that you run your Docker containers in a secure way.

1. The CIS Benchmark

The default Docker installation does not provide us enough security for usage in production. Neither are the numerous examples of Dockerfiles you can find on the web. Even the Dockerfiles in some of our previous blog posts are not production ready. How do we know what to do in order to run our Docker container in a secure way? This brings us to the Center of Internet Security (CIS). The CIS provides best practices for securing IT systems and data against attacks. These best practices are identified and verified by a community of experienced IT professionals. In our case, we will take a look at the CIS Benchmarks page. Here we find a lot of benchmarks for operating systems, devices and software. Within this list, the CDocker Community Edition 1.1.0 is available. It is freely downloadable, but you do need to provide your contact details and after that, a download link is sent to your email address. This will also give you access to the other CIS benchmarks.

Within the CIS benchmark, you will find recommendations grouped by:

  • Host configuration;
  • Docker daemon configuration;
  • Docker daemon configuration files;
  • Container Images and Build File;
  • Container Runtime;
  • Docker Security Operations;
  • Docker Swarm Configuration.

Every recommendation contains a description, a way to check whether it is applicable for your Docker installation and, most important, how you can solve it. A recommendation can have a scoring status. When you comply to the recommendation, this recommendation will increase your overall benchmark score. When you don’t comply, the overall benchmark score will decrease. This only accounts for the recommendations which have a scoring status. The higher the overall benchmark score, the more secure your installation is.

2. Docker Bench for Security

We could check all of the recommendations manually, but wouldn’t it be great when a tool would do this for us? That is where Docker Bench for Security comes to the rescue. Docker Bench for Security tests the CIS Benchmark recommendations for us automatically. A report is generated which gives us the necessary information which recommendations to take a look at.

3. In Practice

Let’s take a look at how this works. We will use the following configuration:

The Docker image we will be using, is a Docker image from a previous post which is available on Docker Hub. The image is based on the openjdk 10 image and contains a simple Spring Boot Web MVC application containing 1 http endpoint: http://ipaddress:8080/hello. This will return a Hello Kubernetes welcome message. The following Dockerfile is defined:

FROM openjdk:10-jdk
VOLUME /tmp
ARG JAR_FILE
ADD ${JAR_FILE} app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]

First thing to do is to run our container:

$ docker run --name=mykubernetesplanet mydeveloperplanet/mykubernetesplanet:0.0.2-SNAPSHOT

After successful start, verify whether you can access the url. The IP address of your Docker container can be obtained with command:

$ docker inspect mykubernetesplanet

In the Networks section, the IP Address of the Docker container can be found.

3.1 Run Docker Bench for Security

The easiest way to run Docker Bench for Security, is to make use of the pre-built container:

$ docker run -it --net host --pid host --userns host --cap-add audit_control \
    -e DOCKER_CONTENT_TRUST=$DOCKER_CONTENT_TRUST \
    -v /var/lib:/var/lib \
    -v /var/run/docker.sock:/var/run/docker.sock \
    -v /usr/lib/systemd:/usr/lib/systemd \
    -v /etc:/etc --label docker_bench_security \
    docker/docker-bench-security

The following report is generated:

# ------------------------------------------------------------------------------
# Docker Bench for Security v1.3.4
#
# Docker, Inc. (c) 2015-
#
# Checks for dozens of common best-practices around deploying Docker containers in production.
# Inspired by the CIS Docker Community Edition Benchmark v1.1.0.
# ------------------------------------------------------------------------------

Initializing Mon Dec 24 11:20:27 UTC 2018
...
[INFO] 4 - Container Images and Build File
[WARN] 4.1  - Ensure a user for the container has been created
[WARN]      * Running as root: quizzical_noether
[WARN]      * Running as root: mykubernetesplanet
[NOTE] 4.2  - Ensure that containers use trusted base images
[NOTE] 4.3  - Ensure unnecessary packages are not installed in the container
[NOTE] 4.4  - Ensure images are scanned and rebuilt to include security patches
[WARN] 4.5  - Ensure Content trust for Docker is Enabled
[WARN] 4.6  - Ensure HEALTHCHECK instructions have been added to the container image
[WARN]      * No Healthcheck found: [mydeveloperplanet/mykubernetesplanet:0.0.2-SNAPSHOT]
[INFO] 4.7  - Ensure update instructions are not use alone in the Dockerfile
[INFO]      * Update instruction found: [mydeveloperplanet/mykubernetesplanet:0.0.2-SNAPSHOT]
[NOTE] 4.8  - Ensure setuid and setgid permissions are removed in the images
[INFO] 4.9  - Ensure COPY is used instead of ADD in Dockerfile
[INFO]      * ADD in image history: [docker/docker-bench-security:latest]
[INFO]      * ADD in image history: [mydeveloperplanet/mykubernetesplanet:0.0.2-SNAPSHOT]
[NOTE] 4.10  - Ensure secrets are not stored in Dockerfiles
[NOTE] 4.11  - Ensure verified packages are only Installed
...
[INFO] Checks: 105
[INFO] Score: 5

Only the section concerning the Container Images and Build File is listed for brevity and because we will use this section in the next paragraphs. As you can see, we have some warnings and notes. The warnings are recommendations which have a scoring status, the notes are recommendations which do not have a scoring status. At the end, we can see our overall scoring status, which is not very high. All running containers are analyzed, thus also the Docker Bench for Security container.

3.2 Fix Some Recommendations

Based on the output, we can easily fix some issues which exist in our Dockerfile. As mentioned before, the CIS Benchmark recommendations contain a remediation for the warning and we will use this for fixing the issues. We increase the version in our pom file and make the changes in branch feature/dockerbenchsecurity, the sources can be found at GitHub.

3.2.1 Ensure a user for the container has been created

Since we did not create a user for our container, our application is now running as root. We don’t want this because root has many privileges and it is not necessary to run our application as root. We add the user appuser to our Dockerfile to fix this warning:

RUN useradd -d /home/appuser -m -s /bin/bash appuser
USER appuser

3.2.2 Ensure HEALTHCHECK instructions have been added to the container image

With the health check, it is possible for the Docker engine to monitor the status of the Docker container. The engine will have the possibility to restart the Docker container or start new instances of it. We are using Spring Boot and we also added Spring Actuator in our pom file. Spring Actuator contains a health check url which we can use for this purpose. We define the health check in our Dockerfile:

HEALTHCHECK --interval=5m --timeout=3s CMD curl -f http://localhost:8080/actuator/health/ || exit 1

3.2.3 Ensure COPY is used instead of ADD in Dockerfile

The last thing we will fix is to use COPY instead of ADD. Both are nearly the same, but COPY is more explicit. The line containing the ADD command:

ADD ${JAR_FILE} app.jar

is changed into:

COPY ${JAR_FILE} app.jar

3.3 Run the Analysis Again

We build our application again in order to generate a new Docker image with mvn clean install. Next, stop our running container and remove it.

$ docker stop mykubernetesplanet
$ docker rm mykubernetesplanet

Start a new container with our new Docker image:

$ docker run --name=mykubernetesplanet mydeveloperplanet/mykubernetesplanet:0.0.3-SNAPSHOT

Now run the Docker Bench for Security:

[INFO] 4 - Container Images and Build File
[PASS] 4.1 - Ensure a user for the container has been created
[NOTE] 4.2 - Ensure that containers use trusted base images
[NOTE] 4.3 - Ensure unnecessary packages are not installed in the container
[NOTE] 4.4 - Ensure images are scanned and rebuilt to include security patches
[WARN] 4.5 - Ensure Content trust for Docker is Enabled
[WARN] 4.6 - Ensure HEALTHCHECK instructions have been added to the container image
[WARN] * No Healthcheck found: [openjdk:10-jdk]
[WARN] * No Healthcheck found: [mydeveloperplanet/mykubernetesplanet:0.0.2-SNAPSHOT]
[INFO] 4.7 - Ensure update instructions are not use alone in the Dockerfile
[INFO] * Update instruction found: [mydeveloperplanet/mykubernetesplanet:0.0.3-SNAPSHOT]
[INFO] * Update instruction found: [openjdk:10-jdk]
[INFO] * Update instruction found: [mydeveloperplanet/mykubernetesplanet:0.0.2-SNAPSHOT]
[NOTE] 4.8 - Ensure setuid and setgid permissions are removed in the images
[INFO] 4.9 - Ensure COPY is used instead of ADD in Dockerfile
[INFO] * ADD in image history: [mydeveloperplanet/mykubernetesplanet:0.0.3-SNAPSHOT]
[INFO] * ADD in image history: [docker/docker-bench-security:latest]
[INFO] * ADD in image history: [openjdk:10-jdk]
[INFO] * ADD in image history: [mydeveloperplanet/mykubernetesplanet:0.0.2-SNAPSHOT]
[NOTE] 4.10 - Ensure secrets are not stored in Dockerfiles
[NOTE] 4.11 - Ensure verified packages are only Installed

The warning concerning the user has changed to PASS and our image with version 0.0.3-SNAPSHOT does not raise a warning anymore concerning the health check. We still have an INFO about the COPY instruction, but that’s because it is still in our image history. We know, however, that we have fixed it and therefore we can leave it this way. Our overall score is increased to 20, which is already slightly better than 5 😉 .

4. Conclusion

In this post we looked at the CIS Benchmark for Docker and how it how it can be automatically checked with the help of Docker Bench for Security. Before running Docker containers in production, it is advised to take a close look at the recommendations. This way, you can be more confident about running Docker in production.