How to keep secure your Docker Image
Tags: docker, security, container
Published: 2019-06-14 15:17:09

---
title: How to keep secure your Docker Image
published: true
description: This is to tell you that how to check docker security
tags: docker, security, container
---

# Overviews

Containers are one of the best tools in recent years.
But it hasn't been established for DevSecOps for containers. Many organizations are unable to keep secure containers' ecosystem.

This article aims to what is the security best practices Docker Images.

Do you know [Clair](https://github.com/coreos/clair) and [Docker Bench for Security](https://github.com/docker/docker-bench-security)? but It's insufficient.

# TL;DL

- __CIS Benchmarks published Docker security checkpoints__
- __Check your images by Dockle and Trivy__
- __Easy to check in CI before docker push__

# CIS Benchmarks
One of the best security best practice provided by The Center for Internet Security(CIS).
Their `Container Images and Build File` has 11 checkpoints.

1. Create a user for the container 
2. Use trusted base images for containers
3. Do not install unnecessary packages in the container
4. Scan and rebuild the images to include security patches
5. Enable Content trust for Docker
6. Add HEALTHCHECK instruction to the container image
7. Do not use update instructions alone in the Dockerfile
8. Remove setuid and setgid permissions in the images
9. Use COPY instead of ADD in Dockerfile
10. Do not store secrets in Dockerfiles
11. Install verified packages only

Clair only supports `Scan and rebuild the images to include security patches`.

# What is `Dockle`

`Dockle` is `Simple Security Auditing and helping build the Best Docker Image` tool.

|  | [Dockle](https://github.com/goodwithtech/dockle) | [Docker Bench for Security](https://github.com/docker/docker-bench-security) | [Clair](https://github.com/coreos/clair) | [Trivy](https://github.com/knqyf263/trivy) | 
|---|:---:|:---:|:---:|:---:|
| 1.  Create a user for the container | ✅ | ✅ | - |- |
| 2.  Use trusted base images for containers | - | - | - |- |
| 3.  Do not install unnecessary packages in the container | - | - | - | - |
| 4.  Scan and rebuild the images to include security patches | - | - | ✅ | ✅ |
| 5.  Enable Content trust for Docker | ✅ | ✅ | - |- |
| 6.  Add HEALTHCHECK instruction to the container image | ✅ | ✅ | - |- |
| 7.  Do not use update instructions alone in the Dockerfile | ✅ | ✅ | -|- |
| 8.  Remove setuid and setgid permissions in the images | ✅ | - | - |- |
| 9.  Use COPY instead of ADD in Dockerfile | ✅ | ✅ | - |- |
| 10. Do not store secrets in Dockerfiles | ✅ | - | - |- |
| 11. Install verified packages only | -  |  - | - |- |

and `Dockle` can detect [CVE-2019-5021](https://blog.aquasec.com/cve-2019-5021-alpine-docker-image-vulnerability) and some other securityholes.

# Use Dockle

You can start easy!

## 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
```

You can check installation [here](https://github.com/goodwithtech/dockle#installation).

Run Result is here.
![passed](https://github.com/goodwithtech/dockle/raw/master/imgs/usage_pass_light.png)
![failed](https://github.com/goodwithtech/dockle/raw/master/imgs/usage_pass_light.png)


# Check in CI

You can use [Trivy](https://github.com/knqyf263/trivy) instead of [Clair](https://github.com/coreos/clair).
Trivy is easy to start and supports library packages and better accuracy than Clair.


## CircleCI

```yaml
jobs:
  build:
    docker:
      - image: docker:18.09-git
    steps:
      - checkout
      - setup_remote_docker
      - restore_cache:
          key: vulnerability-db
      - run:
          name: Build image
          command: docker build -t ci-test:${CIRCLE_SHA1} .
      - run:
          name: Install dockle
          command: |
            apk add --update curl
            VERSION=$(
                curl --silent "https://api.github.com/repos/goodwithtech/dockle/releases/latest" | \
                grep '"tag_name":' | \
                sed -E 's/.*"v([^"]+)".*/\1/'
            )

            wget https://github.com/goodwithtech/dockle/releases/download/v${VERSION}/dockle_${VERSION}_Linux-64bit.tar.gz
            tar zxvf dockle_${VERSION}_Linux-64bit.tar.gz
            mv dockle /usr/local/bin
      - run:
          name: Scan the local image with dockle
          command: dockle --exit-code 1 ci-test:${CIRCLE_SHA1}          
         
      - run:
          name: Install trivy
          command: |
            apk add --update curl
            VERSION=$(
                curl --silent "https://api.github.com/repos/knqyf263/trivy/releases/latest" | \
                grep '"tag_name":' | \
                sed -E 's/.*"v([^"]+)".*/\1/'
            )
            wget https://github.com/knqyf263/trivy/releases/download/v${VERSION}/trivy_${VERSION}_Linux-64bit.tar.gz
            tar zxvf trivy_${VERSION}_Linux-64bit.tar.gz
            mv trivy /usr/local/bin
      - run:
          name: Scan the local image with trivy
          command: trivy --exit-code 1 --quiet --auto-refresh trivy-ci-test:${CIRCLE_SHA1}
      - save_cache:
          key: vulnerability-db
          paths:
            - $HOME/.cache/trivy
workflows:
  version: 2
  release:
    jobs:
      - build
```

## TravisCI

```yaml
services:
  - docker

env:
  global:
    - COMMIT=${TRAVIS_COMMIT::8}

before_install:
  - docker build -t ci-test:${COMMIT} .
  - export DOCKLE_VERSION=$(curl --silent "https://api.github.com/repos/goodwithtech/dockle/releases/latest" | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/\1/')
  - wget https://github.com/goodwithtech/dockle/releases/download/v${DOCKLE_VERSION}/dockle_${DOCKLE_VERSION}_Linux-64bit.tar.gz
  - tar zxvf dockle_${DOCKLE_VERSION}_Linux-64bit.tar.gz
  - export TRIVY_VERSION=$(curl --silent "https://api.github.com/repos/knqyf263/trivy/releases/latest" | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/\1/')
  - wget https://github.com/knqyf263/trivy/releases/download/v${TRIVY_VERSION}/trivy_${TRIVY_VERSION}_Linux-64bit.tar.gz
  - tar zxvf trivy_${TRIVY_VERSION}_Linux-64bit.tar.gz
script:
  - ./dockle --exit-code 1 ci-test:${COMMIT}
  - ./trivy --exit-code 1 --quiet --auto-refresh ci-test:${COMMIT}
cache:
  directories:
    - $HOME/.cache/trivy
```

# Conclusion

You can check your Docker Container Images to use `Dockle` and `Trivy`!
These are OSS tools.

If you feel like I missed something, got some details wrong, or just want to say hi, please feel free to leave a comment below or reach out to me on [GitHub](https://github.com/tomoyamachi) or [Twitter](https://twitter.com/tomoyamachi).