distrolessイメージを活用してECRスキャンの脆弱性を撲滅する。

distroless イメージを活用して脆弱性を撲滅する

ECRにはイメージスキャンの機能があります。 これは、コンテナイメージに対してセキュリティスキャンを行い、脆弱性を洗い出してくれる機能です。

Amazon ECR は、オープンソースの Clair プロジェクトの共通脆弱性識別子 (CVE) データベースを使用します。ベーシックスキャンでは、プッシュ時にスキャンするようにリポジトリを設定します。手動スキャンを実行すると Amazon ECR によってスキャン結果のリストが提供されます。

from https://dev.classmethod.jp/articles/ecr-repository-scan/

先日、セキュリティの勉強会があり、コンテナセキュリティについても話題が挙がりました。 私はそこでECRのイメージスキャン機能を知り、さっそくプロジェクトで使用しているコンテナイメージをスキャンすることにしました...。

すると...

from https://dev.classmethod.jp/articles/ecr-repository-scan/

(画像は参考です。)200件を超える情報提供と、1件のクリティカルな脆弱性が見つかってしまいました。 クリティカルな脆弱性の内容はzlib1gに関する内容でDebian系のlinuxディストリビューションで見つかるらしいです。

from https://ubuntu.com/security/notices/USN-5355-2

そこで今回は「distroless」と呼ばれるイメージを使用して、脆弱性を撲滅していきたいと思います。

distroless とは何か

distrolessは超軽量なコンテナイメージです。 distrolessにはアプリケーションと、アプリを動かすランタイムしか存在しません。bashshもありません。 脆弱性を生み出すパッケージマネージャーやシェルなどがそもそも存在しないため、これ単体だと使い勝手は悪いですが、高度なセキュリティ要件にも対応できます。

"Distroless" images contain only your application and its runtime dependencies. They do not contain package managers, shells or any other programs you would expect to find in a standard Linux distribution.

軽量なコンテナといえばalpine linuxもありますが、distrolessは比較にならないぐらい軽いImageです。 (そもそも近年のalpine linuxは少々重たくなってきましたし、その割には使い勝手もあまりよくない気がします...)

ではこのdistrolessを使用してコンテナイメージの脆弱性を撲滅していきたいと思います。

distroless と マルチステージビルド の適応方法

distrolessの運用のためには、マルチステージビルドというベストプラクティスを使用します。 distrolessにはbashcatlsもないため、デバッグなどには不向きです。 そのため、開発段階のイメージファイルとしては避けた方よいです。 しかし、本番環境では開発段階のイメージを活用すると脆弱性につながりかねないので、distrolessイメージと開発用イメージをうまく使い分けなければいけません。 そこで、マルチステージビルドを用いて、2段階のビルドを行います。

distrolessおよびマルチステージビルドを導入する前のDockerfileは以下の形状でした。

FROM python3.9.18
WORKDIR /app
COPY ./app /app
RUN pip install --upgrade pip
RUN pip install -r requirements.txt
ENTRYPOINT "entrypoint.sh"

この状態だと、python3.9.18脆弱性がすべてECRに反映されてしまいます。 (今回はpython3.9.18のベースイメージがDebian系でしたので、debian系の脆弱性が出現してしまいました) ですので、マルチステージビルドを導入して、この脆弱性を隠そうと思います。

FROM python3.9.18 AS dev
WORKDIR /app
COPY ./app /app
RUN pip install --upgrade pip
RUN pip install -r requirements.txt
ENTRYPOINT "entrypoint.sh"

FROM gcr.io/distroless/python3 AS prod
COPY --from=dev ./app /app
COPY --from=dev /usr/local/lib/python3.9/site-packages /usr/local/lib/python3.9/dist-packages
ENTRYPOINT ["sh", "-c", "python -uB -m gunicorn myapp.wisgi --config /app/gunicorn_settings.py"]

このように、マルチステージビルドを応用することで、ECRイメージの脆弱性の数を減らすことが出来ます。 最終的に、脆弱性は「なし」のステータスにすることができました。