CLOVER🍀

That was when it all began.

Dockerコンテナイメージのセキュリティ診断ツール、Dockleを試す

これは、なにをしたくて書いたもの?

Dockerイメージのセキュリティ診断ツールのひとつとして、「Dockle」というものがあるのを知りまして。

こちらをちょっと試してみようかな、と。

Dockle?

コンテナイメージに含まれるパッケージ等の脆弱性診断ツールとして、ClairやTrivyが有名です。

GitHub - quay/clair: Vulnerability Static Analysis for Containers

GitHub - aquasecurity/trivy: A Simple and Comprehensive Vulnerability Scanner for Containers, Suitable for CI

Dockleはこういうものとはちょっと違って、CIS BenchmarkのDockerに関する項目(Container Images and Build File)や
DockerfileのBest Practiceで重要なものをチェックしてくれるツールのようです。

GitHub - goodwithtech/dockle: Container Image Linter for Security, Helping build the Best-Practice Docker Image, Easy to start

CIで簡単につかえるコンテナのセキュリティ診断「Dockle」 - Qiita

CIS Benchmarks

Best practices for writing Dockerfiles | Docker Documentation

実際のチェック内容は、こちら。

dockle/CHECKPOINT.md at v0.3.1 · goodwithtech/dockle · GitHub

ざっくり書いていってみましょう。

  • Dockerイメージ用のチェックポイント
    • Create a user for the container … コンテナ用のユーザーを作成しているか
    • Use trusted base images for containers … 信頼されたベースイメージを使っているか
    • Enable Content trust for Docker … Docker Content Trustが有効化されているか
    • Add HEALTHCHECK instruction to the container image … コンテナイメージに HEALTHCHECK が指定されているか
    • Do not use update instructions alone in the Dockerfile … パッケージマネージャーのupdateコマンドを、単一のコマンドで実行していないか
    • Confirm safety of setuid and setgid files … setuid、setgidファイルの安全性を確認しているか
    • Use COPY instead of ADD in Dockerfile … ADDの代わりにCOPYを使っているか
    • Do not store secrets in Dockerfiles … Dockerfileに機密情報を書き込んでいないか
  • Docker用のチェックポイント
    • Avoid sudo command … sudoコマンドを使っていないか
    • Avoid sensitive directory mounting … センシティブなディレクトリのマウントを使っていないか
    • Avoid apt-get upgrade, apk upgrade, dist-upgrade … パッケージマネージャーのupgradeコマンドを使っていないか
    • Use apk add with --no-cache … apk addには--no-cacheオプションを使っているか
    • Clear apt-get caches … パッケージマネージャーのキャッシュをクリアしているか
    • Avoid latest tag … latestタグを使っていないか
  • Linux用のチェックポイント
    • Avoid empty password … 空のパスワードを使っていないか
    • Be unique UID/GROUPs … UIDおよびグループはユニークか
    • Only put necessary files … 必要なファイルのみが置かれているか

使い方の例は、こちら。

Common Examples

CIへの統合例は、こちら。

Continuous Integration (CI)

こんな感じですね。では、使っていってみましょう。

環境

今回の環境は、こちら。

$ uname -srvmpio
Linux 5.4.0-47-generic #51-Ubuntu SMP Fri Sep 4 19:50:52 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux


$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 20.04.1 LTS
Release:    20.04
Codename:   focal


$ docker version
Client: Docker Engine - Community
 Version:           19.03.12
 API version:       1.40
 Go version:        go1.13.10
 Git commit:        48a66213fe
 Built:             Mon Jun 22 15:45:44 2020
 OS/Arch:           linux/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          19.03.12
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.13.10
  Git commit:       48a66213fe
  Built:            Mon Jun 22 15:44:15 2020
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.2.13
  GitCommit:        7ad184331fa3e55e52b890ea95e65ba581ae3429
 runc:
  Version:          1.0.0-rc10
  GitCommit:        dc9208a3303feef5b3839f4323d9beb36df0a9dd
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683

インストール

まずは、インストールしてみます。

Installation

Ubuntu Linuxの場合の手順はこちら。

Debian/Ubuntu

$ VERSION=$(
 curl --silent "https://api.github.com/repos/goodwithtech/dockle/releases/latest" | \
 grep '"tag_name":' | \
 sed -E 's/.*"v([^"]+)".*/\1/' \
) && curl -L -o dockle.deb https://github.com/goodwithtech/dockle/releases/download/v${VERSION}/dockle_${VERSION}_Linux-64bit.deb
$ sudo dpkg -i dockle.deb && rm dockle.deb

今回インストールしたDockleは、0.3.1です。

$ dockle -v
dockle version 0.3.1

オプションを確認。

$ dockle -h
NAME:
  dockle - Container Image Linter for Security, Helping build the Best-Practice Docker Image, Easy to start
USAGE:
  dockle [options] image_name
VERSION:
  0.3.1
OPTIONS:
  --input value                 input file path instead of image name
  --ignore value, -i value      checkpoints to ignore. You can use .dockleignore too.
  --format value, -f value      format (json)
  --output value, -o value      output file name
  --exit-code value, -c value   exit code when alert were found (default: 0)
  --exit-level value, -l value  change ABEND level when use exit-code=1 (default: "WARN")
  --debug, -d                   debug mode
  --timeout value, -t value     docker timeout. e.g) 5s, 5m... (default: 1m30s)
  --authurl value               registry authenticate url
  --username value              registry login username
  --password value              registry login password. Using --password via CLI is insecure.
  --insecure                    registry connect insecure
  --nonssl                      registry connect without ssl
  --cache-dir value             cache directory
  --help, -h                    show help
  --version, -v                 print the version

Dockleの実行自体には、Dockerは不要なようです。

使ってみる

では、使ってみましょう。

試しに、Apache MavenのDockerイメージをPull。

$ docker image pull maven:3.6-adoptopenjdk-11

Dockleを実行してみます。

$ dockle maven:3.6-adoptopenjdk-11

こんな結果になりました。

WARN  - CIS-DI-0001: Create a user for the container
    * Last user should not be root
INFO    - CIS-DI-0005: Enable Content trust for Docker
    * export DOCKER_CONTENT_TRUST=1 before docker pull/build
INFO    - CIS-DI-0006: Add HEALTHCHECK instruction to the container image
    * not found HEALTHCHECK statement
INFO    - CIS-DI-0008: Confirm safety of setuid/setgid files
    * setuid file: usr/bin/newgrp urwxr-xr-x
    * setgid file: usr/bin/expiry grwxr-xr-x
    * setuid file: bin/umount urwxr-xr-x
    * setgid file: sbin/pam_extrausers_chkpwd grwxr-xr-x
    * setgid file: usr/bin/wall grwxr-xr-x
    * setgid file: usr/bin/ssh-agent grwxr-xr-x
    * setuid file: usr/bin/passwd urwxr-xr-x
    * setuid file: usr/bin/gpasswd urwxr-xr-x
    * setuid file: bin/su urwxr-xr-x
    * setuid file: usr/bin/chsh urwxr-xr-x
    * setuid file: usr/bin/chfn urwxr-xr-x
    * setgid file: usr/bin/chage grwxr-xr-x
    * setuid file: usr/lib/openssh/ssh-keysign urwxr-xr-x
    * setuid file: bin/mount urwxr-xr-x
    * setgid file: sbin/unix_chkpwd grwxr-xr-x

もうひとつ、Apacheで試してみましょう。

$ docker image pull httpd:2.4

結果。

$ dockle httpd:2.4
WARN    - CIS-DI-0001: Create a user for the container
    * Last user should not be root
INFO    - CIS-DI-0005: Enable Content trust for Docker
    * export DOCKER_CONTENT_TRUST=1 before docker pull/build
INFO    - CIS-DI-0006: Add HEALTHCHECK instruction to the container image
    * not found HEALTHCHECK statement
INFO    - CIS-DI-0008: Confirm safety of setuid/setgid files
    * setgid file: usr/bin/expiry grwxr-xr-x
    * setuid file: usr/bin/gpasswd urwxr-xr-x
    * setuid file: bin/su urwxr-xr-x
    * setuid file: usr/bin/chsh urwxr-xr-x
    * setgid file: sbin/unix_chkpwd grwxr-xr-x
    * setgid file: usr/bin/chage grwxr-xr-x
    * setgid file: usr/bin/wall grwxr-xr-x
    * setuid file: usr/bin/passwd urwxr-xr-x
    * setuid file: usr/bin/chfn urwxr-xr-x
    * setuid file: usr/local/apache2/bin/suexec urwxr-xr-x
    * setuid file: bin/umount urwxr-xr-x
    * setuid file: bin/mount urwxr-xr-x
    * setuid file: usr/bin/newgrp urwxr-xr-x

今回選んだイメージでは、引っかかるチェックポイントは変わりませんでした…。

なお、「コンテナ内のプロセスがrootで実行されてるよ」というチェックポイントですが、Apacheの場合は子プロセスはrootで
動作しないので、ここは許容してもよいかも?という気がします。

ここをさらに木にする場合は、User namespaceを使うのだとか。

Isolate containers with a user namespace | Docker Documentation

余談でした。

実行時間は、こんな感じ。

$ time dockle maven:3.6-adoptopenjdk-11

real    0m16.873s
user    0m2.095s
sys 0m0.944s


$ time dockle httpd:2.4

real    0m4.910s
user    0m0.658s
sys 0m0.212s

あとは、指定のレベル以上のアラートが出た場合の終了コードを指定したり、特定のチェックポイントを無視したり、

Common Examples

結果をJSONで出力したりできるようです。

$ dockle -f json maven:3.6-adoptopenjdk-11
{
  "summary": {
    "fatal": 0,
    "warn": 1,
    "info": 3,
    "skip": 0,
    "pass": 12
  },
  "details": [
    {
      "code": "CIS-DI-0001",
      "title": "Create a user for the container",
      "level": "WARN",
      "alerts": [
        "Last user should not be root"
      ]
    },
    {
      "code": "CIS-DI-0005",
      "title": "Enable Content trust for Docker",
      "level": "INFO",
      "alerts": [
        "export DOCKER_CONTENT_TRUST=1 before docker pull/build"
      ]
    },
    {
      "code": "CIS-DI-0006",
      "title": "Add HEALTHCHECK instruction to the container image",
      "level": "INFO",
      "alerts": [
        "not found HEALTHCHECK statement"
      ]
    },
    {
      "code": "CIS-DI-0008",
      "title": "Confirm safety of setuid/setgid files",
      "level": "INFO",
      "alerts": [
        "setuid file: usr/bin/passwd urwxr-xr-x",
        "setgid file: usr/bin/wall grwxr-xr-x",
        "setuid file: bin/mount urwxr-xr-x",
        "setgid file: sbin/unix_chkpwd grwxr-xr-x",
        "setgid file: usr/bin/chage grwxr-xr-x",
        "setuid file: usr/bin/chsh urwxr-xr-x",
        "setgid file: usr/bin/ssh-agent grwxr-xr-x",
        "setuid file: usr/lib/openssh/ssh-keysign urwxr-xr-x",
        "setuid file: usr/bin/chfn urwxr-xr-x",
        "setuid file: usr/bin/newgrp urwxr-xr-x",
        "setgid file: usr/bin/expiry grwxr-xr-x",
        "setuid file: usr/bin/gpasswd urwxr-xr-x",
        "setuid file: bin/umount urwxr-xr-x",
        "setuid file: bin/su urwxr-xr-x",
        "setgid file: sbin/pam_extrausers_chkpwd grwxr-xr-x"
      ]
    }
  ]
}

良いですね、コンテナイメージのBest Practiceに従っているかどうかなどを確認してみるといいのかなーと思います。