The One Thing You Should Do After Building Best-Practice Docker Image (in 3 minutes)
Tags: docker, security, development
Published: 2019-06-19 14:48:22

---
title: The One Thing You Should Do After Building Best-Practice Docker Image (in 3 minutes)
published: true
cover_image: https://www.goodwith.tech/static/assets/img/dockle_blog_logo.png
tags: docker, security, development
canonical_url: 
---

# Overview

Today, many companies tried to use Docker. This article is for wrote/writing [best-practice Dockerfiles](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/).

I created a tool analyzes your Dockerfile via the built image in 3 minutes.
[<img src="https://github.com/goodwithtech/dockle/raw/master/imgs/logo.png" width="450">](https://github.com/goodwithtech/dockle)
> [Dockle - Container Image Linter for Security, Helping build the Best-Practice Docker Image, Easy to start](https://github.com/goodwithtech/dockle)

Dockle is able to check deeply. (file permissions, credential files...) So, Dockle the best tool to check important rules, especially for security.

(I'm also the main committer of [Vuls](https://github.com/future-architect/vuls) and [Trivy](https://github.com/knqyf263/trivy). These are famous vulnerability scanners.)


It's __NOT__ a Dockerfile Linter (like a hadolint).<br />
It's able to check security risks on a container base image too. Dockerfile Linter never does it.

I hope you [star it](https://github.com/goodwithtech/dockle)!

# How to use

## Homebrew ([Mac](https://brew.sh/) / [Linux](https://docs.brew.sh/Homebrew-on-Linux))

```bash
$ export DOCKER_CONTENT_TRUST=1
$ docker build -t test-image:v1 .
$ brew install goodwithtech/dockle/dockle
$ dockle test-image:v1
```
## Linux

```bash
$ export DOCKER_CONTENT_TRUST=1
$ docker build -t test-image:v1 .
$ VERSION=$(
 curl --silent "https://api.github.com/repos/goodwithtech/dockle/releases/latest" | \
 grep '"tag_name":' | \
 sed -E 's/.*"v([^"]+)".*/\1/' \
) && curl -L -o dockle.tar.gz https://github.com/goodwithtech/dockle/releases/download/v${VERSION}/dockle_${VERSION}_Linux-64bit.tar.gz
$ tar zxvf dockle.tar.gz
$ ./dockle test-image:v1
```

## Windows

```bash
$ export DOCKER_CONTENT_TRUST=1
$ docker build -t test-image:v1 .
$ VERSION=$(
 curl --silent "https://api.github.com/repos/goodwithtech/dockle/releases/latest" | \
 grep '"tag_name":' | \
 sed -E 's/.*"v([^"]+)".*/\1/' \
) && curl -L -o dockle.zip https://github.com/goodwithtech/dockle/releases/download/v${VERSION}/dockle_${VERSION}_Windows-64bit.zip
$ unzip dockle.zip && rm dockle.zip
$ ./dockle.exe test-image:v1
```

## via Docker

```bash
$ VERSION=$(
 curl --silent "https://api.github.com/repos/goodwithtech/dockle/releases/latest" | \
 grep '"tag_name":' | \
 sed -E 's/.*"v([^"]+)".*/\1/' \
) && docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
 goodwithtech/dockle:v${VERSION} test-image:v1
```

You only need -v /var/run/docker.sock:/var/run/docker.sock when you'd like to scan the image on your host machine.

# Results

```yaml
PASS    - CIS-DI-0001: Create a user for the container
PASS    - CIS-DI-0005: Enable Content trust for Docker
PASS    - CIS-DI-0006: Add HEALTHCHECK instruction to the container image
PASS    - CIS-DI-0007: Do not use update instructions alone in the Dockerfile
PASS    - CIS-DI-0008: Remove setuid and setgid permissions in the images
PASS    - CIS-DI-0009: Use COPY instead of ADD in Dockerfile
PASS    - CIS-DI-0010: Do not store secrets in ENVIRONMENT variables
PASS    - CIS-DI-0010: Do not store secret files
PASS    - DKL-DI-0001: Avoid sudo command
PASS    - DKL-DI-0002: Avoid sensitive directory mounting
PASS    - DKL-DI-0003: Avoid apt-get/apk/dist-upgrade
PASS    - DKL-DI-0004: Use apk add with --no-cache
PASS    - DKL-DI-0005: Clear apt-get caches
PASS    - DKL-DI-0006: Avoid latest tag
PASS    - DKL-LI-0001: Avoid empty password
PASS    - DKL-LI-0002: Be unique UID
PASS    - DKL-LI-0002: Be unique GROUP
```

This tool checks [CIS Benchmarks](https://www.cisecurity.org/benchmark/docker/) and [Best practices for writing Dockerfiles
](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/).

Dockle shows short messages suggestions for improvement when there are problems.

```yaml
WARN    - CIS-DI-0001: Create a user for the container
        * Last user should not be root
PASS    - CIS-DI-0005: Enable Content trust for Docker
WARN    - CIS-DI-0006: Add HEALTHCHECK instruction to the container image
        * not found HEALTHCHECK statement
PASS    - CIS-DI-0007: Do not use update instructions alone in the Dockerfile
INFO    - CIS-DI-0008: Remove setuid and setgid permissions in the images
        * Found setuid file: usr/lib/openssh/ssh-keysign urwxr-xr-x
FATAL   - CIS-DI-0009: Use COPY instead of ADD in Dockerfile
        * Use COPY : /bin/sh -c #(nop) ADD file:81c0a803075715d1a6b4f75a29f8a01b21cc170cfc1bff6702317d1be2fe71a3 in /app/credentials.json
FATAL   - CIS-DI-0010: Do not store secrets in ENVIRONMENT variables
        * Suspicious ENV key found : MYSQL_PASSWD
FATAL   - CIS-DI-0010: Do not store secret files
        * Suspicious filename found : app/credentials.json
PASS    - DKL-DI-0001: Avoid sudo command
FATAL   - DKL-DI-0002: Avoid sensitive directory mounting
        * Avoid mounting sensitive dirs : /usr
PASS    - DKL-DI-0003: Avoid apt-get/apk/dist-upgrade
PASS    - DKL-DI-0004: Use apk add with --no-cache
FATAL   - DKL-DI-0005: Clear apt-get caches
        * Use 'rm -rf /var/lib/apt/lists' after 'apt-get install' : /bin/sh -c apt-get update && apt-get install -y git
PASS    - DKL-DI-0006: Avoid latest tag
FATAL   - DKL-LI-0001: Avoid empty password
        * No password user found! username : nopasswd
PASS    - DKL-LI-0002: Be unique UID
PASS    - DKL-LI-0002: Be unique GROUP
```

You can check details to searching analysys codes(`CIS-DI-0001`...) on [README](https://github.com/goodwithtech/dockle#checkpoint-detail). 

You don't mind if your image doesn't pass checkpoints.
It's one of an indicator.

Sometimes you have to run as `root`.<br/>
Sometimes CLI tool doesn't need `HEALTHCHECK`.<br/>
Sometimes use `ADD` statement when you'd like to add tar files.


I hope this is reminder that really you'd like to do so.

You can be specified to ignore rules to give `--ignore, -i` option or create `.dockleignore`.

```
$ dockle -i CIS-DI-0001 -i CIS-DI-0006 [IMAGE_NAME]
```

```shell:.dockleignore
# run as root
CIS-DI-0001
# don't use HEALTHCHECK
CIS-DI-0006
# use latest tag
DKL-DI-0006
```

Let's do it again.

```yaml
IGNORE  - CIS-DI-0001: Create a user for the container
INFO    - CIS-DI-0005: Enable Content trust for Docker
        * export DOCKER_CONTENT_TRUST=1 before docker pull/build
IGNORE  - CIS-DI-0006: Add HEALTHCHECK instruction to the container image
PASS    - CIS-DI-0007: Do not use update instructions alone in the Dockerfile
INFO    - CIS-DI-0008: Remove setuid and setgid permissions in the images
        * Found setuid file: usr/lib/openssh/ssh-keysign urwxr-xr-x
IGNORE  - CIS-DI-0009: Use COPY instead of ADD in Dockerfile
FATAL   - CIS-DI-0010: Do not store secrets in ENVIRONMENT variables
        * Suspicious ENV key found : MYSQL_PASSWD
FATAL   - CIS-DI-0010: Do not store secret files
        * Suspicious filename found : app/credentials.json
PASS    - DKL-DI-0001: Avoid sudo command
FATAL   - DKL-DI-0002: Avoid sensitive directory mounting
        * Avoid mounting sensitive dirs : /usr
PASS    - DKL-DI-0003: Avoid apt-get/apk/dist-upgrade
PASS    - DKL-DI-0004: Use apk add with --no-cache
FATAL   - DKL-DI-0005: Clear apt-get caches
        * Use 'rm -rf /var/lib/apt/lists' after 'apt-get install' : /bin/sh -c apt-get update && apt-get install -y git
PASS    - DKL-DI-0006: Avoid latest tag
FATAL   - DKL-LI-0001: Avoid empty password
        * No password user found! username : nopasswd
PASS    - DKL-LI-0002: Be unique UID
PASS    - DKL-LI-0002: Be unique GROUP
```

# Closing

Dockle is __NOT__ a Dockerfile Linter, but a Docker Image Linter.

Dockle can check deeply. (file permissions, credential files...) So, Dockle is able to check important rules than others, especially for security.

And Dockle is able to analyze an image created by stdin, too. You could use it in many places.

```shell
docker build -<<EOF
FROM busybox
RUN echo "hello world"
EOF
```


I hope you [like it](https://github.com/goodwithtech/dockle)!

Thanks!!