コンテナ脆弱性検査ツール「Dockle」エラー集

概要

コンテナイメージの脆弱性検査・セキュリティ診断ツール「Dockle」で出会ったエラーを何点かご紹介します。


※タイトルでエラー集と書いておりますが、遭遇したエラーを何点か書いているだけであって、決してエラーを網羅しているわけではございません。(すみません。。。)


目次

目次


Dockle

Dockleとは

Dockleとは、コンテナイメージの脆弱性検査・診断ツールであり、Dockerfileをビルドしたイメージ内の脆弱性に対して警告・対処法などを提案してくれるツールになります。

github.com


インストール方法

公式のREADMEにコマンドが掲載されていてわかりやすいかと思います。

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


Dockle使用例

こんなDockerfileがあったとします。

FROM ubuntu:20.04

RUN \
    apt-get update \
    && apt-get -y install \
    curl


こちらをビルドしたイメージに対してDockleで検査してみます。

$ docker build . -t dockle-test

$ dockle dockle-test


するとDockleによる脆弱性検査が始まり・・・

2022-07-02T19:32:07.244+0900    INFO    Failed to check latest version. not found version patterns
FATAL   - DKL-DI-0005: Clear apt-get caches
        * Use 'rm -rf /var/lib/apt/lists' after 'apt-get install|update' : RUN /bin/sh -c apt-get update     && apt-get -y install     curl # buildkit
WARN    - CIS-DI-0001: Create a user for the container
        * Last user should not be root
WARN    - DKL-DI-0006: Avoid latest tag
        * Avoid 'latest' tag
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: urwxr-xr-x usr/bin/mount
        * setuid file: urwxr-xr-x usr/bin/newgrp
        * setuid file: urwxr-xr-x usr/bin/chsh
        * setuid file: urwxr-xr-x usr/bin/su
        * setgid file: grwxr-xr-x usr/sbin/pam_extrausers_chkpwd
        * setuid file: urwxr-xr-x usr/bin/gpasswd
        * setuid file: urwxr-xr-x usr/bin/umount
        * setuid file: urwxr-xr-x usr/bin/chfn
        * setgid file: grwxr-xr-x usr/sbin/unix_chkpwd
        * setgid file: grwxr-xr-x usr/bin/chage
        * setgid file: grwxr-xr-x usr/bin/wall
        * setgid file: grwxr-xr-x usr/bin/expiry
        * setuid file: urwxr-xr-x usr/bin/passwd


apt-getのキャッシュをクリアしましょうとか。

FATAL   - DKL-DI-0005: Clear apt-get caches
        * Use 'rm -rf /var/lib/apt/lists' after 'apt-get install|update' : RUN /bin/sh -c apt-get update     && apt-get -y install     curl # buildkit


ルートユーザでの実行はよくないよとか。

WARN    - CIS-DI-0001: Create a user for the container
        * Last user should not be root


latestタグやめましょうとか。

WARN    - DKL-DI-0006: Avoid latest tag
        * Avoid 'latest' tag


こんな具合に色々と検査してくれます。


前提

本記事でご紹介するDockleエラーの実行に関する前提のお話になります。


最終的にAWSのECSやApp Runnerで動かすために、ビルドしたイメージをECRへプッシュするCI/CDというシチュエーションになります。

CI/CD、つまり本記事で実行するビルドスクリプトは、Alpineのコンテナ(docker:latestイメージ)で実行しています。

また、こちらで使用しているDockleのバージョンは「0.4.5」になります。


Dockleエラーのご紹介

私がDockleを使用する上で遭遇したエラーを何点かご紹介します。


Requested image not foundエラー

以下のようなdockerビルド・Dockleインストール/実行してみると、Dockle実行でエラーメッセージが出力されました。

DOCKLE_DIR_PATH="./dockle"

repositoryName="bastion-ecr"
accountId=$(aws sts get-caller-identity --query "Account" --output text)
repositoryEnddpoint="${accountId}.dkr.ecr.ap-northeast-1.amazonaws.com"
repositoryUri="${repositoryEnddpoint}/${repositoryName}"


ecrTag="$(git rev-parse HEAD)"
docker build -t ${repositoryName} .
docker tag ${repositoryName}:latest ${repositoryUri}:${ecrTag}

if [ ! -d ${DOCKLE_DIR_PATH} ]; then
    mkdir -p ${DOCKLE_DIR_PATH}
    VERSION=$(
        curl --silent "https://api.github.com/repos/goodwithtech/dockle/releases/latest" | \
        grep '"tag_name":' | \
        sed -E 's/.*"v([^"]+)".*/\1/' \
    )

    curl -L -o ${DOCKLE_DIR_PATH}/dockle.tar.gz https://github.com/goodwithtech/dockle/releases/download/v${VERSION}/dockle_${VERSION}_Linux-64bit.tar.gz
    tar zxvf ${DOCKLE_DIR_PATH}/dockle.tar.gz -C ${DOCKLE_DIR_PATH}
fi

${DOCKLE_DIR_PATH}/dockle ${repositoryUri}:${ecrTag}
2022-07-02T12:07:35.651Z INFO    Failed to check latest version. not found version patterns
2022-07-02T12:07:37.020Z    FATAL   unable to initialize a image struct: failed to initialize source: reading manifest xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx in 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/bastion-ecr: manifest unknown: Requested image not found


ビルドしたイメージにECRのリポジトリURIとコミットハッシュでタグを付与し、そのイメージをDockleで検査したかったのですが、タグ付けしたローカルのビルドイメージを見に行けていないのでRequested image not foundになっているようです。

プライベートレジストリ(ECR)を見に行こうとしてるってことですかね。(となるとこの挙動が正しいってこと?まだpushしていないのでECRにイメージはない。)

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


なので仕方なく、ローカルイメージに対してDockleを実行するようにします。

※後述する項目でローカルイメージ指定ではなくても実行できるようになります。


- ${DOCKLE_DIR_PATH}/dockle ${repositoryUri}:${ecrTag}
+ ${DOCKLE_DIR_PATH}/dockle ${repositoryName}:latest

すると、無事通るようになりました。

いえ、今度は別のエラーが出ました。次項で説明します。

2022-07-02T10:43:01.157Z INFO    Failed to check latest version. not found version patterns
2022-07-02T10:43:01.414Z    FATAL   unable to initialize a image struct: failed to initialize source: reading manifest latest in docker.io/library/bastion-ecr: errors:
denied: requested access to the resource is denied
unauthorized: authentication required


unauthorizedエラー

先程の上記エラーですが、unauthorizedエラーといった出力のようです。


こちらなのですが、Dockleのissueに似たような現象がありました。

Upgrading to v0.3.1 Results in Fatal Error · Issue #77 · goodwithtech/dockle · GitHub


パッケージインストールではなく、Docker Hubで公開されているDockleのイメージで実行するように、とのことだそうです。

dockleVersion=$(
   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 \
    -v $(pwd)/.dockleignore:/.dockleignore \
    goodwithtech/dockle:v${dockleVersion} \
    ${repositoryName}:latest


実際にやってみたら。。。


いけました!!!

パッケージインストールでエラーになる理由はわかりませんが、とりあえずエラーは解消したのでdocker実行でいこうと思います。


※公式にdockerでの実行方法のコマンドが記載されています。

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


AWS regionエラー

1つ目のエラーで、Dockleの実行対象イメージ(タグ)を${repositoryUri}:${ecrTag}から${repositoryName}:latestにしていました。

先程Dockleをインストールパッケージではなくdockerイメージでの実行にしたので、希望を込めてDockleコマンドを元に戻して実行してみました。

docker run \
    --rm \
    -v /var/run/docker.sock:/var/run/docker.sock \
    -v $(pwd)/.dockleignore:/.dockleignore \
    goodwithtech/dockle:v${dockleVersion} \
-   ${repositoryName}:latest
+   ${repositoryUri}:${ecrTag}


すると、先程のエラーはなくなりましたが、また別のエラーが出ました。

2022/07/02 00:37:57 ERROR: unable to resolve endpoint for service "api.ecr", region "", err: UnknownEndpointError: could not resolve endpoint
partition: "aws", service: "api.ecr", region: "", known: [ap-southeast-2 eu-west-1 eu-west-3 us-east-1 us-west-2 ap-northeast-1 ap-northeast-2 me-south-1 ap-east-1 eu-north-1 us-east-2 us-west-1 ap-south-1 ca-central-1 eu-west-2 sa-east-1 ap-southeast-1 eu-central-1]


このエラーですが、どうやらAWSの内容に関わるエラーのようです。

region ""という点から、Dockleコンテナ内でデフォルトリージョンが設定されていないからだという推測をしました。


Dockleコンテナのイメージは提供されたものをそのまま使いたいため、コンテナの実行時に-eオプションで環境変数を指定することにしました。

+REGION="ap-northeast-1"

docker run \
    --rm \
    -v /var/run/docker.sock:/var/run/docker.sock \
    -v $(pwd)/.dockleignore:/.dockleignore \
+   -e AWS_DEFAULT_REGION=${REGION} \
    goodwithtech/dockle:v${dockleVersion} \
    ${repositoryUri}:${ecrTag}


すると、先程のエラーが出力されなくなりました。


.dockleignoreファイルが反映されない?

先程までは一つのエラーを対処するとまた別のエラーが出るといった連鎖関係でしたが、ようやく落ち着きました。

ここで今度は、Dockle実行の際に、検出対象から除外したいFATAL, WARNがあったため、それらのルールを指定することで除外してみます。


方法としては、公式に記載されているのですが、以下の3つのパターンがあります。

  • dockleコマンドのオプションでの--ignore,-i
  • DOCKLE_IGNORES環境変数
  • .dockleignoreファイル

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


ルールの増減の際にdockleコマンドが入ったスクリプトファイルに差分が生まれるのが嫌だったため、.dockleignoreファイルスクリプトファイル外で管理することにしました。


以下のように、.dockleignoreファイルを作成し、各ルールが何にあたるのかというコメントアウトもつけてみました。

DKL-DI-0005 # Clear apt-get caches
CIS-DI-0001 # Create a user for the container


すると、、、

指定したはずのルールが除外できておらず、検出されてしまっていました。

FATAL    - DKL-DI-0005: Clear apt-get caches
    * Use 'rm -rf /var/lib/apt/lists' after 'apt-get install|update' : RUN /bin/sh -c apt-get update     && apt-get -y install     curl     jq     unzip # buildkit
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
...
...(省略)


これは色々と試したのですが、行の途中からでもコメントアウトされていると行全体が読み込まれないということがわかりました。


以下のように修正をして再度実行すると、想定通り、指定したルールに該当するメッセージは出力されませんでした。

# Clear apt-get caches
DKL-DI-0005

# Create a user for the container
CIS-DI-0001 
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
...
...(省略)


補足

上記の検証例では、実は検査結果にFATAL,WARNが検出されても異常終了されず、EXITステータスが0で正常終了されていました。

もし脆弱性の検出の際にDockleプロセスを異常終了させたい場合、--exit-code 1というオプションがあります。

 docker run \
        --rm \
        -v /var/run/docker.sock:/var/run/docker.sock \
        -v $(pwd)/.dockleignore:/.dockleignore \
        -e AWS_DEFAULT_REGION=${REGION} \
        goodwithtech/dockle:v${VERSION} \
+       --exit-code 1 \
        ${ECR_RepositoryUri}:${ECR_Tag}


公式リンクになります。

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


また、上記の場合、WARNかFATALを検出したときに異常終了する仕様がデフォルトとなっています。

例えばもし、異常終了するエラーレベルをFATALのみにしたいなどあれば、--exit-levelオプションにて指定することもできます。

 docker run \
        --rm \
        -v /var/run/docker.sock:/var/run/docker.sock \
        -v $(pwd)/.dockleignore:/.dockleignore \
        -e AWS_DEFAULT_REGION=${REGION} \
        goodwithtech/dockle:v${VERSION} \
        --exit-code 1 \
+       --exit-level "FATAL" \
        ${ECR_RepositoryUri}:${ECR_Tag}


公式リンクになります。

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


最後に

Dockleというdockerの脆弱性検査ツール、簡単に使えると思ってすぐ導入してみたのですが、意外と色々なエラーに当たる上にまだネットに情報も少なく、中々調べてもわからず苦労しました。

しかしこれでようやく導入できるようになったので、簡単に導入できて心強いツールと言えるようになりました!

コンテナの脆弱性検査の手法は色々ありますが、どの手法であれど脆弱性検査は大事ですね。