概要
コンテナイメージの脆弱性検査・セキュリティ診断ツール「Dockle」で出会ったエラーを何点かご紹介します。
※タイトルでエラー集と書いておりますが、遭遇したエラーを何点か書いているだけであって、決してエラーを網羅しているわけではございません。(すみません。。。)
目次
Dockle
Dockleとは
Dockleとは、コンテナイメージの脆弱性検査・診断ツールであり、Dockerfileをビルドしたイメージ内の脆弱性に対して警告・対処法などを提案してくれるツールになります。
インストール方法
公式のREADMEにコマンドが掲載されていてわかりやすいかと思います。
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にイメージはない。)
なので仕方なく、ローカルイメージに対して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での実行方法のコマンドが記載されています。
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ファイル
ルールの増減の際に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}
公式リンクになります。
また、上記の場合、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}
公式リンクになります。
最後に
Dockleというdockerの脆弱性検査ツール、簡単に使えると思ってすぐ導入してみたのですが、意外と色々なエラーに当たる上にまだネットに情報も少なく、中々調べてもわからず苦労しました。
しかしこれでようやく導入できるようになったので、簡単に導入できて心強いツールと言えるようになりました!
コンテナの脆弱性検査の手法は色々ありますが、どの手法であれど脆弱性検査は大事ですね。