Ubuntu 20.04 で docker scan をやってみた

# はじめに

Ubuntu 20.04 で docker scan をやってみました。

doceker scan は CLI 上からイメージの脆弱性を検査する docker コマンドの機能です。

<https://codezine.jp/article/detail/14347>

スキャナは snyk の脆弱性スキャン SaaS を利用しています。
docker CLI はイメージの情報を syk のサーバに送信して、スキャン結果を出力することをやってくれます。

# 環境

動作環境は以下のとおりです。

```bash:Ubuntu
$ cat /etc/os-release 
NAME="Ubuntu"
VERSION="20.04.2 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.2 LTS"
VERSION_ID="20.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal
```

```bash:docker
$ docker --version
Docker version 20.10.11, build dea9396

$ docker scan --version
Version:    v0.9.0
Git commit: b05830d
Provider:   Snyk (1.563.0 (standalone))
```

# スキャンしようとするが・・・

Docker のマニュアルに沿ってとりあえずスキャンしようとしたもののいくつかエラーが出ました・・・。

<https://matsuand.github.io/docs.docker.jp.onthefly/engine/scan/>

順番に処置していきましょう。

## ログインを要求された

スキャンの前に DockerHub へのログインを要求されました。

```bash:エラー
$ docker scan hello-world
Docker Scan relies upon access to Snyk, a third party provider, do you consent to proceed using Snyk? (y/N)
y
failed to get DockerScanID: You need to be logged in to Docker Hub to use scan feature.
please login to Docker Hub using the Docker Login command
```

`docker scan` は DockerHub の無料アカウントを持っていると毎月 10 回まで無料で実行できる機能です。

有償アカウントだとさらにスキャンできる回数が増えます。

とりあえず `docker login` しましょう。

```bash:回避策
$ docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: ******
Password: 
WARNING! Your password will be stored unencrypted in /home/******/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded
```

## 400 bad request

`docker login` 後にスキャンしようとするものの、ふたたびエラーが出ました。

```bash
$ docker scan hello-world
failed to get DockerScanID: bad status code "400 Bad Request"
```

`docker scan` は、 snyk の脆弱性スキャン SaaS を使用するツールで、snyk のアカウントを作らないとスキャンできません。

DockerScanID というのは snyk のアカウントのことのようです。メンドクサイですね。

`--login` オプションで snyk にスキャンします。

```bash
$ docker scan --login
To authenticate your account, open the below URL in your browser.
After your authentication is complete, return to this prompt to start using Snyk.
https://snyk.io/login?******
```

表示された URL をブラウザで表示します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114392/6c39450a-436b-0c91-16f4-4e8555e2c54f.png)

Docker ID と紐づけたいので、`Docker ID` ボタンをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114392/8d124329-4de6-ac48-a10d-3b79a7b461ad.png)

`Authenticate` ボタンをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114392/b92c7134-7e3d-255d-f3fd-56e4cd31481f.png)

認証されました。

しかし、コマンドラインを見ると認証失敗のエラーが出てます。

```bash
Authentication failed. Please check the API token on https://snyk.io
```

よくわかりませんね・・・。

以下のサイトを参考に

<https://qiita.com/yomon8/items/e5c1b20719b5c6f7911f>

ブラウザで snyk にログインして、

<https://app.snyk.io/account>

アカウント設定画面から `click to show` をクリックして、API キーを表示します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114392/b9af253f-6d49-2540-db4d-7ab3b10c8c04.png)

`--token` オプションの引数に API キーを指定してログインを実行します。

```bash
$ docker scan --login --token ****************************
Your account has been authenticated. Snyk is now ready to be used.
```

これでようやくスキャンの準備が整いました。

# スキャン実行

## 脆弱性を含まないイメージをスキャンする

docker 公式のイメージ `hello-world` をスキャンしてみます。

```bash
$ docker scan hello-world

Testing hello-world...

Organization:      kannkyo
Package manager:   linux
Project name:      docker-image|hello-world
Docker image:      hello-world
Platform:          linux/amd64
Licenses:          enabled

✓ Tested hello-world for known issues, no vulnerable paths found.

Note that we do not currently have vulnerability data for your image.
```

脆弱性が検出されませんでした。
安全なイメージですね。

## 脆弱性を含むイメージをスキャンする

docker 公式のイメージ `httpd:2.4.51` をスキャンしてみます。
脅威度の高い脆弱性だけを対象とするため、`--severity=high` オプションをつけました。

```bash
$ docker scan --severity=high httpd:2.4.51

Testing httpd:2.4.51...

✗ High severity vulnerability found in curl/libcurl4
  Description: Cleartext Transmission of Sensitive Information
  Info: https://snyk.io/vuln/SNYK-DEBIAN11-CURL-1585138
  Introduced through: curl/libcurl4@7.74.0-1.3+b1
  From: curl/libcurl4@7.74.0-1.3+b1
  Image layer: Introduced by your base image (httpd:2.4.51-bullseye)

✗ Critical severity vulnerability found in glibc/libc-bin
  Description: Use After Free
  Info: https://snyk.io/vuln/SNYK-DEBIAN11-GLIBC-1296898
  Introduced through: glibc/libc-bin@2.31-13+deb11u2, meta-common-packages@meta
  From: glibc/libc-bin@2.31-13+deb11u2
  From: meta-common-packages@meta > glibc/libc6@2.31-13+deb11u2
  Image layer: Introduced by your base image (httpd:2.4.51-bullseye)

✗ Critical severity vulnerability found in curl/libcurl4
  Description: Double Free
  Info: https://snyk.io/vuln/SNYK-DEBIAN11-CURL-1585150
  Introduced through: curl/libcurl4@7.74.0-1.3+b1
  From: curl/libcurl4@7.74.0-1.3+b1
  Image layer: Introduced by your base image (httpd:2.4.51-bullseye)

Organization:      kannkyo
Package manager:   deb
Project name:      docker-image|httpd
Docker image:      httpd:2.4.51
Platform:          linux/amd64
Base image:        httpd:2.4.51-bullseye
Licenses:          enabled

Tested 115 dependencies for known issues, found 3 issues.

According to our scan, you are currently using the most secure version of the selected base image
```

実行ログの最後の 2 行がスキャン結果のサマリーです。

> Tested 115 dependencies for known issues, found 3 issues.
>
> 115の依存関係について既知の問題をテストし、3つの問題を発見しました。
>
> According to our scan, you are currently using the most secure version of the selected base image
>
> スキャンの結果、お客様は現在、選択されたベースイメージの最も安全なバージョンを使用しています。

curl, gtlibc についての 3 つの脆弱性が発見されました。

また、脆弱性が含まれるものの、`httpd` イメージの中では最も安全なバージョンを使用していることがわかりました。

3 つの脆弱性の詳細を見てみます。

| パッケージ     | 脆弱性                                                                                                              | CVE                                                                             | 脅威度 |
| -------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | ------ |
| curl/libcurl4  | [Cleartext Transmission of Sensitive Information in curl](https://security.snyk.io/vuln/SNYK-DEBIAN11-CURL-1585138) | [CVE-2021-22946](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-22946) | 7.5    |
| glibc/libc-bin | [Use After Free in glibc](https://security.snyk.io/vuln/SNYK-DEBIAN11-GLIBC-1296898)                                | [CVE-2021-33574](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-33574) | 9.8    |
| curl/libcurl4  | [Double Free in curl](https://security.snyk.io/vuln/SNYK-DEBIAN11-CURL-1585150)                                     | [CVE-2021-22945](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-22945) | 9.1    |

curl と glibc についての脆弱性が出てます。

脅威度は最大で 10 です。9.8 はかなり高いです。

使わないパッケージであれば、`httpd` イメージから削除した別のイメージを作ったほうが良いです。

## Dockerfileとベースイメージに脆弱性を含むイメージをスキャンする

次に、ベースイメージに先程の `httpd:2.4.51` を使用し、さらに Dockerfile に脆弱性を埋め込んだイメージをスキャンします。

スキャン対象のイメージの Dockerfile は以下です。

<https://github.com/kannkyo/buggy-docker/blob/v0.0.1/Dockerfile>

```bash
$ docker scan ghcr.io/kannkyo/buggy-docker:v0.0.1

Testing ghcr.io/kannkyo/buggy-docker:v0.0.1...

✗ Low severity vulnerability found in tar
  Description: CVE-2005-2541
  Info: https://snyk.io/vuln/SNYK-DEBIAN11-TAR-523480
  Introduced through: meta-common-packages@meta
  From: meta-common-packages@meta > tar@1.34+dfsg-1

✗ Low severity vulnerability found in systemd/libsystemd0
  Description: Authentication Bypass
  Info: https://snyk.io/vuln/SNYK-DEBIAN11-SYSTEMD-1291054
  Introduced through: systemd/libsystemd0@247.3-6, apt@2.2.4, util-linux/bsdutils@1:2.36.1-8, util-linux/mount@2.36.1-8, systemd/libudev1@247.3-6
  From: systemd/libsystemd0@247.3-6
  From: apt@2.2.4 > systemd/libsystemd0@247.3-6
  From: util-linux/bsdutils@1:2.36.1-8 > systemd/libsystemd0@247.3-6
  and 5 more...

...

✗ Medium severity vulnerability found in curl/libcurl4
  Description: Insufficient Verification of Data Authenticity
  Info: https://snyk.io/vuln/SNYK-DEBIAN11-CURL-1585148
  Introduced through: curl/libcurl4@7.74.0-1.3+b1
  From: curl/libcurl4@7.74.0-1.3+b1

✗ High severity vulnerability found in curl/libcurl4
  Description: Cleartext Transmission of Sensitive Information
  Info: https://snyk.io/vuln/SNYK-DEBIAN11-CURL-1585138
  Introduced through: curl/libcurl4@7.74.0-1.3+b1
  From: curl/libcurl4@7.74.0-1.3+b1

✗ Critical severity vulnerability found in glibc/libc-bin
  Description: Use After Free
  Info: https://snyk.io/vuln/SNYK-DEBIAN11-GLIBC-1296898
  Introduced through: glibc/libc-bin@2.31-13+deb11u2, meta-common-packages@meta
  From: glibc/libc-bin@2.31-13+deb11u2
  From: meta-common-packages@meta > glibc/libc6@2.31-13+deb11u2

✗ Critical severity vulnerability found in curl/libcurl4
  Description: Double Free
  Info: https://snyk.io/vuln/SNYK-DEBIAN11-CURL-1585150
  Introduced through: curl/libcurl4@7.74.0-1.3+b1
  From: curl/libcurl4@7.74.0-1.3+b1

Organization:      kannkyo
Package manager:   deb
Project name:      docker-image|ghcr.io/kannkyo/buggy-docker
Docker image:      ghcr.io/kannkyo/buggy-docker:v0.0.1
Platform:          linux/amd64
Base image:        httpd:2.4.51-bullseye
Licenses:          enabled

Tested 115 dependencies for known issues, found 52 issues.

According to our scan, you are currently using the most secure version of the selected base image
```

[詳細なログはこちら](https://github.com/kannkyo/buggy-docker/blob/main/reports/docker-scan/v0.0.1.md#docker-scan-ghcriokannkyobuggy-dockerv001)

52 件の脆弱性が検出されました。

多すぎてよくわからないので、`docker scan` コマンドのオプションを使ってもう少し調べてみます。

## ベースイメージの脆弱性を対象外にする

`--exclude-base` オプションを使用して、ベースイメージ `httpd` の脆弱性を対象外にします。

これで、自分が作った Dockerfile による脆弱性だけを抽出します。

```bash
$ docker scan --file Dockerfile --exclude-base ghcr.io/kannkyo/buggy-docker:v0.0.1

Testing ghcr.io/kannkyo/buggy-docker:v0.0.1...

Organization:      kannkyo
Package manager:   deb
Target file:       /app/Dockerfile
Project name:      docker-image|ghcr.io/kannkyo/buggy-docker
Docker image:      ghcr.io/kannkyo/buggy-docker:v0.0.1
Platform:          linux/amd64
Base image:        httpd:2.4.51
Licenses:          enabled

Tested 115 dependencies for known issues, found 0 issues.

According to our scan, you are currently using the most secure version of the selected base image
```

脆弱性が検出されませんでした。

どうやら Dockerfile についての脆弱性は検出できないようです。

## 脅威度の高い脆弱性の情報を詳細に出力する

`--serverity` オプションと `--dependency-tree` オプションを使って次の脅威度の脆弱性を含むパッケージの情報を詳細に出力します。

`--dependency-tree` オプションは、脆弱性の依存関係を可視化するオプションです。

```bash
$ docker scan --dependency-tree --severity=high ghcr.io/kannkyo/buggy-docker:v0.0.1
docker-image|ghcr.io/kannkyo/buggy-docker @ v0.0.1
...
   ├─ curl/libcurl4 @ 7.74.0-1.3+b1
   │  ├─ brotli/libbrotli1 @ 1.0.9-2+b2
   │  ├─ krb5/libgssapi-krb5-2 @ 1.18.3-6+deb11u1
   │  │  ├─ e2fsprogs/libcom-err2 @ 1.46.2-2
   │  │  ├─ krb5/libk5crypto3 @ 1.18.3-6+deb11u1
   │  │  └─ krb5/libkrb5-3 @ 1.18.3-6+deb11u1
   │  │     ├─ e2fsprogs/libcom-err2 @ 1.46.2-2
   │  │     ├─ keyutils/libkeyutils1 @ 1.6.1-2
   │  │     ├─ krb5/libk5crypto3 @ 1.18.3-6+deb11u1
   │  │     └─ openssl/libssl1.1 @ 1.1.1k-1+deb11u1
   │  ├─ libidn2/libidn2-0 @ 2.3.0-5
   │  ├─ libpsl/libpsl5 @ 0.21.0-1.2
   │  │  ├─ libidn2/libidn2-0 @ 2.3.0-5
   │  │  └─ libunistring/libunistring2 @ 0.9.10-4
   │  ├─ libssh2/libssh2-1 @ 1.9.0-2
   │  │  └─ libgcrypt20 @ 1.8.7-6
   │  │     └─ libgpg-error/libgpg-error0 @ 1.38-2
   │  ├─ nghttp2/libnghttp2-14 @ 1.43.0-1
   │  ├─ openldap/libldap-2.4-2 @ 2.4.57+dfsg-3
   │  ├─ openssl/libssl1.1 @ 1.1.1k-1+deb11u1
   │  └─ rtmpdump/librtmp1 @ 2.4+20151223.gitfa8646d.1-2+b2
   │     ├─ gmp/libgmp10 @ 2:6.2.1+dfsg-1
   │     ├─ gnutls28/libgnutls30 @ 3.7.1-5
   │     ├─ nettle/libhogweed6 @ 3.7.3-1
   │     └─ nettle/libnettle8 @ 3.7.3-1
...
   ├─ glibc/libc-bin @ 2.31-13+deb11u2
...
   └─ xxhash/libxxhash0 @ 0.8.0-2

Testing ghcr.io/kannkyo/buggy-docker:v0.0.1...

✗ High severity vulnerability found in curl/libcurl4
  Description: Cleartext Transmission of Sensitive Information
  Info: https://snyk.io/vuln/SNYK-DEBIAN11-CURL-1585138
  Introduced through: curl/libcurl4@7.74.0-1.3+b1
  From: curl/libcurl4@7.74.0-1.3+b1

✗ Critical severity vulnerability found in glibc/libc-bin
  Description: Use After Free
  Info: https://snyk.io/vuln/SNYK-DEBIAN11-GLIBC-1296898
  Introduced through: glibc/libc-bin@2.31-13+deb11u2, meta-common-packages@meta
  From: glibc/libc-bin@2.31-13+deb11u2
  From: meta-common-packages@meta > glibc/libc6@2.31-13+deb11u2

✗ Critical severity vulnerability found in curl/libcurl4
  Description: Double Free
  Info: https://snyk.io/vuln/SNYK-DEBIAN11-CURL-1585150
  Introduced through: curl/libcurl4@7.74.0-1.3+b1
  From: curl/libcurl4@7.74.0-1.3+b1

Organization:      kannkyo
Package manager:   deb
Project name:      docker-image|ghcr.io/kannkyo/buggy-docker
Docker image:      ghcr.io/kannkyo/buggy-docker:v0.0.1
Platform:          linux/amd64
Base image:        httpd:2.4.51-bullseye
Licenses:          enabled

Tested 115 dependencies for known issues, found 3 issues.

According to our scan, you are currently using the most secure version of the selected base image
```

すべての脆弱性の依存関係が出力されました。 `--severity` オプションを併用しても、依存関係をフィルタできないみたいですね。

## 脆弱性を含むイメージをスキャンする

Dockerfile の中で `cron` パッケージをインストールしたパッケージを作成します。

<https://github.com/kannkyo/buggy-docker/blob/v0.0.2/Dockerfile#L15>

`cron` をインストールする際に、`exim4-config` がインストールされます。

```bash
$ apt-get install cron
The following NEW packages will be installed:
  ca-certificates cron exim4-base exim4-config exim4-daemon-light gsasl-common guile-2.2-libs libevent-2.1-7 libfribidi0 libgc1
  libgnutls-dane0 libgpm2 libgsasl7 libidn11 libltdl7 libmailutils7 libmariadb3 libmpdec3 libncurses6 libncursesw6 libntlm0 libpython3.9
  libpython3.9-minimal libpython3.9-stdlib libreadline8 libsqlite3-0 libunbound8 mailutils mailutils-common mariadb-common media-types
  mysql-common netbase openssl psmisc readline-common sensible-utils
0 upgraded, 37 newly installed, 0 to remove and 0 not upgraded.
```

`exim4-config` は、インジェクション攻撃に対する脆弱性 [CVE-2021-38371](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-38371) を含んでいます。

新しいイメージをスキャンします。

```bash
$ docker scan --severity=high ghcr.io/kannkyo/buggy-docker:v0.0.2

Testing ghcr.io/kannkyo/buggy-docker:v0.0.2...

✗ High severity vulnerability found in exim4/exim4-config
  Description: Arbitrary Code Injection
  Info: https://snyk.io/vuln/SNYK-DEBIAN11-EXIM4-1538494
  Introduced through: exim4/exim4-config@4.94.2-7, exim4/exim4-base@4.94.2-7, exim4/exim4-daemon-light@4.94.2-7
  From: exim4/exim4-config@4.94.2-7
  From: exim4/exim4-base@4.94.2-7 > exim4/exim4-config@4.94.2-7
  From: exim4/exim4-base@4.94.2-7
  and 2 more...
  Image layer: Introduced by your base image (httpd:2.4.51-bullseye)

✗ High severity vulnerability found in curl/libcurl4
  Description: Cleartext Transmission of Sensitive Information
  Info: https://snyk.io/vuln/SNYK-DEBIAN11-CURL-1585138
  Introduced through: curl/libcurl4@7.74.0-1.3+b1
  From: curl/libcurl4@7.74.0-1.3+b1
  Image layer: Introduced by your base image (httpd:2.4.51-bullseye)

✗ Critical severity vulnerability found in python3.9/libpython3.9-minimal
  Description: Improper Input Validation
  Info: https://snyk.io/vuln/SNYK-DEBIAN11-PYTHON39-1290158
  Introduced through: python3.9/libpython3.9-minimal@3.9.2-1, mailutils/libmailutils7@1:3.10-3+b1, python3.9/libpython3.9-stdlib@3.9.2-1, python3.9/libpython3.9@3.9.2-1
  From: python3.9/libpython3.9-minimal@3.9.2-1
  From: mailutils/libmailutils7@1:3.10-3+b1 > python3.9/libpython3.9@3.9.2-1 > python3.9/libpython3.9-stdlib@3.9.2-1 > python3.9/libpython3.9-minimal@3.9.2-1
  From: python3.9/libpython3.9-stdlib@3.9.2-1
  and 3 more...
  Image layer: Introduced by your base image (httpd:2.4.51-bullseye)

✗ Critical severity vulnerability found in glibc/libc-bin
  Description: Use After Free
  Info: https://snyk.io/vuln/SNYK-DEBIAN11-GLIBC-1296898
  Introduced through: glibc/libc-bin@2.31-13+deb11u2, meta-common-packages@meta
  From: glibc/libc-bin@2.31-13+deb11u2
  From: meta-common-packages@meta > glibc/libc6@2.31-13+deb11u2
  Image layer: Introduced by your base image (httpd:2.4.51-bullseye)

✗ Critical severity vulnerability found in curl/libcurl4
  Description: Double Free
  Info: https://snyk.io/vuln/SNYK-DEBIAN11-CURL-1585150
  Introduced through: curl/libcurl4@7.74.0-1.3+b1
  From: curl/libcurl4@7.74.0-1.3+b1
  Image layer: Introduced by your base image (httpd:2.4.51-bullseye)

Organization:      kannkyo
Package manager:   deb
Project name:      docker-image|ghcr.io/kannkyo/buggy-docker
Docker image:      ghcr.io/kannkyo/buggy-docker:v0.0.2
Platform:          linux/amd64
Base image:        httpd:2.4.51-bullseye
Licenses:          enabled

Tested 152 dependencies for known issues, found 5 issues.

According to our scan, you are currently using the most secure version of the selected base image

```

新しい脆弱性 2 つを含む 5 つの脆弱性が検出されました。

`exim4-config` だけでなく `libpython3.9-minimal` の脆弱性も検出しました。

新しい脆弱性のスキャン結果をよく見ると、

> Image layer: Introduced by your base image (httpd:2.4.51-bullseye)

「ベースイメージで作り込まれた」と書いてあります。誤検知ですね。

脆弱性そのものは検出できても、脆弱性がどのレイヤーに含まれるかという点の精度は甘いようです。

# 評価

## docker scan の 良い点

- Snyk と Docker のアカウントが連携していて、Docker CLI から snyk の脆弱性をスキャンできるのでツール導入の敷居がグッと低いですね。
- パッケージの依存関係をツリー構造で可視化してくれる機能は、すごく便利です。
  - 他の脆弱性スキャナーの GitHub Code Scanning には、依存関係を可視化する機能はありません。
  - パッケージ A, B, C をインストールした後に、パッケージ A が依存するパッケージ D で脆弱性エラーが出ときとかに解析がすごく楽になります。

## docker scan の 悪い点

- スキャンする前のログイン作業は結構面倒でしたね。もう少しわかりやすくならないのでしょうか。
- パッケージの脆弱性は発見できましたが、Dockerfile の脆弱性は発見できませんでした。
- 脆弱性が含まれるレイヤーの識別の精度が甘いという欠点がありました。

## まとめ

`docker scan` は総じて導入の敷居が低く、簡単にイメージのスキャンができる使いやすいツールでした。

Dockerfile の脆弱性をチェックできる [sysdiglabs/benchmark-dockerfile](https://github.com/sysdiglabs/benchmark-dockerfile) なんかと組み合わせて使えばセキュアなコンテナの開発に役立つかと、思います。

# 参考サイト

<https://snyk.io/learn/docker-security-scanning/>

<https://f.hubspotusercontent10.net/hubfs/1699665/Docker_CLI_Cheat_Sheet_2021-01-12a.PDF>