distrolessでコンテナイメージの脆弱性に対処してみた

記事タイトルとURLをコピーする

G-gen の三浦です。当記事では、distroless という Google が提供するコンテナイメージを使って、イメージの脆弱性に対処する方法を紹介します。

distroless とは

distroless は、Google が提供する Docker コンテナのベースイメージです。不要なコンポーネントを削除した最小限のイメージであり、セキュリティ上のメリットがあります。主な特徴は以下の通りです。

特徴 内容
攻撃対象領域を縮小 OS の不要なファイルやバイナリを削除することで、攻撃対象領域を小さくします。
イメージサイズを削減 イメージが軽量になり、デプロイや転送、コンテナ起動が高速になります。
セキュリティ向上 脆弱性の原因となる不要なコンポーネントを削除します。

distroless は、Ubuntu や Alpine などの汎用的なイメージと比較して、セキュリティに特化しています。

検証の流れ

検証の流れは以下の通りです。

項番 項目 内容
1 検証準備 アプリケーションコードを準備し、必要な API を有効化します。
2 Cloud Run のデプロイと脆弱性件数の確認 まずは Python 3.12 slim を使用して Cloud Run にデプロイし、脆弱性があることを確認します。
3 Dockerfile の変更(distroless 対応) Dockerfile を distroless に対応するように変更します。
4 Cloud Run の再デプロイと脆弱性件数の確認 再度 Cloud Run にデプロイし、一部の脆弱性が解消されたことを確認します。

検証準備

ディレクトリ構成

ディレクトリ構成は以下の通りです。

.
├── Dockerfile
├── main.py
└── requirements.txt

Dockerfile

最初は、ベースイメージとして Python 3.12 slim を使用します。

# ベースイメージとして Python 3.12 slim を使用
FROM python:3.12-slim
 
# 環境変数を設定
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
 
# 作業ディレクトリを設定
WORKDIR /app
 
# 必要な依存関係をインストール
RUN apt-get update && apt-get install -y \
gcc \
&& rm -rf /var/lib/apt/lists/*
 
# 必要な Python パッケージをインストール
COPY requirements.txt /app/
RUN pip install --no-cache-dir -r requirements.txt
 
# アプリケーションコードをコンテナにコピー
COPY . /app
 
# アプリケーションを実行
CMD ["python", "main.py"]

main.py

以下の Python コードを使用します。

from flask import Flask
import os
 
app = Flask(__name__)
 
@app.route("/")
def hello():
return "Hello, Cloud Run!"
 
if __name__ == "__main__":
port = int(os.environ.get("PORT", 8080))
app.run(host="0.0.0.0", port=port)

requirements.txt

flask

API の有効化

イメージの脆弱性スキャンを行う Artifact Analysis の API と Cloud Run 等の各種 API を有効化します。

gcloud services enable \
artifactregistry.googleapis.com \
containerscanning.googleapis.com \
cloudbuild.googleapis.com \
run.googleapis.com

検証

Cloud Run のデプロイと脆弱性件数の確認

環境変数を設定し、Cloud Run をデプロイします。

# 環境変数の設定
export SERVICE_NAME=test-app # イメージと Cloud Run サービス名
 
# Cloud Run のデプロイ
gcloud run deploy $SERVICE_NAME --source . \
--region=asia-northeast1 \
--allow-unauthenticated

Y を入力して Enter を実行すると、Artifact Registry のリポジトリ (cloud-run-source-deploy) が自動的に作成されます。

# 出力例
Deploying from source requires an Artifact Registry Docker repository to store built containers. A repository named [cloud-run-source-deploy] in region [asia-northeast1] will be created.
 
Do you want to continue (Y/n)? Y

デプロイが完了したら、Cloud Run の URL にアクセスし、Web ページが表示されることを確認します。

# 出力例
Service [test-app] revision [test-app-XXXXXX-XXX] has been deployed and is serving 100 percent of traffic.
Service URL: https://xxx-xxx-xxxxxx.asia-northeast1.run.app # Cloud Run の URL

表示確認(Python 3.12 slim)

Google Cloud コンソールにログインし、検索バーにArtifact Registryと入力し、[Artifact Registry] を選択します。

Artifact Registry を選択

[cloud-run-source-deploy] > [イメージ名] へ移動し、表示されている脆弱性の件数を確認します。例では、591 件の脆弱性を確認しています。

脆弱性の件数確認(Python 3.12 slim)

名前の部分を選択し、仮想サイズからイメージの容量を確認します。例では、138MB です。

容量確認(Python 3.12 slim)

[脆弱性]タブで、重大度に応じた件数などの詳細を確認できます。

詳細確認(Python 3.12 slim)

Dockerfile の変更(distroless 対応)

Dockerfile を以下の通りに変更します。この変更では、ビルド用のイメージと実行用のイメージを分離し、distroless イメージを使用します。

# ビルド用イメージ
FROM python:3.12-slim AS builder
 
# 必要なパッケージをインストール
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir --target=/app/libs -r requirements.txt
 
# アプリケーションコードをコピー
COPY main.py /app/
 
# 実行用の Distroless イメージ
FROM gcr.io/distroless/python3-debian12
 
# アプリケーションファイルをコピー
WORKDIR /app
COPY --from=builder /app/libs /app/libs
COPY --from=builder /app/main.py /app/main.py
 
# Pythonのライブラリパスを設定
ENV PYTHONPATH=/app/libs
 
# Python実行環境をENTRYPOINTで指定し、アプリケーションファイルをCMDで指定
ENTRYPOINT ["/usr/bin/python3"]
CMD ["/app/main.py"]

これは Multi-stage builds という方式であり、ビルド用途と実行環境用途で異なるベースイメージを使用しています。

Cloud Run の再デプロイと脆弱性件数の確認

初回と同様に Cloud Run をデプロイします。

gcloud run deploy $SERVICE_NAME --source . \
--region=asia-northeast1 \
--allow-unauthenticated 

Cloud Run の URL にアクセスし、Web ページが表示されることを確認します。

表示確認(distroless)

イメージの脆弱性件数を確認します。例では 21 件となり、先ほどの 591 件と比較して大幅に減っています。

脆弱性の件数確認(distroless)

同様に容量を確認します。例では 20.7MB となり、先ほどの 138MB と比較して大幅に減っています。

容量確認(distroless)

脆弱性の詳細は以下の通りです。

詳細確認(distroless)

三浦 健斗(記事一覧)

クラウドソリューション部

2023年10月よりG-genにジョイン。元オンプレ中心のネットワークエンジニア。ネットワーク・セキュリティ・唐揚げ・辛いものが好き。