performing-container-image-hardening について
本番ワークロードを準備するチーム向けのコンテナイメージ強化スキルです。イメージの縮小、実行時の制限、ベースイメージの固定、スキャン検証を手順化しています。
主な機能
- 01マルチステージビルドの手引き
- 02最小構成と distroless のベースイメージ
- 03未使用コンポーネントの削除
- 04読み取り専用ファイルシステムと非 root 実行
- 05ダイジェストによるベースイメージ固定
- 06Trivy と CIS チェックによる検証
活用シーン
- 01コンテナイメージの攻撃面縮小
- 02本番用イメージの準備
- 03CIS Docker Benchmark との整合確認
- 04最小構成または distroless イメージへの移行
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ mukul975/ anthropic-cybersecurity-skills --skill performing-container-image-hardeningインストール後、Claude Code で/performing-container-image-hardeningを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
LICENSEassets/template.mdreferences/api-reference.mdstandards.mdworkflows.mdscripts/agent.pyprocess.py詳細
コンテナイメージのハードニング
使用する場面
- 攻撃対象領域を最小限に抑えた本番用コンテナイメージを構築する場合
- コンテナ設定で CIS Docker Benchmark への準拠が求められる場合
- 未使用のパッケージによる脆弱性への露出を減らすため、イメージサイズを縮小する場合
- コンテナ化されたワークロードに多層防御を実装する場合
- 大規模なベースイメージから distroless または最小構成のイメージに移行する場合
ランタイムのコンテナセキュリティ監視には使用しないでください(Falco を使用してください)。ホストレベルの Docker デーモンのハードニングには使用しないでください(CIS Docker Benchmark のホストチェックを使用してください)。コンテナオーケストレーションのセキュリティには使用しないでください(Kubernetes セキュリティスキャンを使用してください)。
前提条件
- マルチステージビルド用の Docker または BuildKit
- ベースイメージの選択肢:distroless、Alpine、slim、または scratch
- 検証用のコンテナスキャンツール(Trivy)
- CIS Docker Benchmark のリファレンス
ワークフロー
ステップ 1:マルチステージビルドを使用してイメージサイズを最小化する
# Build stage with all dependencies
FROM python:3.12-bookworm AS builder
WORKDIR /build
COPY requirements.txt .
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt
COPY src/ ./src/
RUN python -m compileall src/
# Production stage with minimal base
FROM python:3.12-slim-bookworm AS production
RUN apt-get update && \
apt-get install -y --no-install-recommends libpq5 && \
rm -rf /var/lib/apt/lists/* && \
apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false
COPY --from=builder /install /usr/local
COPY --from=builder /build/src /app/src
RUN groupadd -r appuser && useradd -r -g appuser -d /app -s /sbin/nologin appuser
RUN chown -R appuser:appuser /app
USER appuser
WORKDIR /app
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8080/health')" || exit 1
EXPOSE 8080
ENTRYPOINT ["python", "-m", "src.main"]
ステップ 2:Distroless ベースイメージを使用する
# Go application with distroless
FROM golang:1.22 AS builder
WORKDIR /app
COPY go.* ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -o /server .
FROM gcr.io/distroless/static-debian12:nonroot
COPY --from=builder /server /server
USER nonroot:nonroot
ENTRYPOINT ["/server"]
ステップ 3:不要なコンポーネントを削除する
# Hardened image checklist
FROM ubuntu:24.04 AS base
RUN apt-get update && \
apt-get install -y --no-install-recommends \
ca-certificates \
libssl3 && \
# Remove package manager to prevent runtime package installation
apt-get purge -y --auto-remove apt dpkg && \
rm -rf /var/lib/apt/lists/* \
/var/cache/apt/* \
/tmp/* \
/var/tmp/* \
/usr/share/doc/* \
/usr/share/man/* \
/usr/share/info/* \
/root/.cache
# Remove shells if not needed
RUN rm -f /bin/sh /bin/bash /usr/bin/sh 2>/dev/null || true
# Remove setuid/setgid binaries
RUN find / -perm /6000 -type f -exec chmod a-s {} + 2>/dev/null || true
ステップ 4:読み取り専用ファイルシステムを設定する
# Kubernetes deployment with read-only root filesystem
apiVersion: apps/v1
kind: Deployment
metadata:
name: hardened-app
spec:
template:
spec:
securityContext:
runAsNonRoot: true
runAsUser: 65534
fsGroup: 65534
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: app:hardened
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
volumeMounts:
- name: tmp
mountPath: /tmp
- name: cache
mountPath: /app/cache
volumes:
- name: tmp
emptyDir:
sizeLimit: 100Mi
- name: cache
emptyDir:
sizeLimit: 50Mi
ステップ 5:ベースイメージをダイジェストで固定する
# Pin to exact image digest for reproducibility
FROM python:3.12-slim-bookworm@sha256:abcdef1234567890 AS production
# This ensures the exact same base image is used every time
ステップ 6:自動スキャンでハードニングを検証する
# Scan hardened image with Trivy
trivy image --severity HIGH,CRITICAL hardened-app:latest
# Check CIS Docker Benchmark compliance
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
aquasec/docker-bench-security
# Verify no root processes
docker run --rm hardened-app:latest whoami
# Expected: appuser (NOT root)
# Verify read-only filesystem
docker run --rm hardened-app:latest touch /test 2>&1
# Expected: Read-only file system error
主な概念
| 用語 | 定義 |
|---|---|
| マルチステージビルド | 複数の FROM ステージを使用してビルドとランタイムを分離し、最終イメージのサイズを削減する Docker のビルド手法 |
| Distroless | アプリケーションとランタイム依存関係のみを含む、Google がメンテナンスする最小構成のコンテナイメージ |
| 非 root ユーザー | コンテナエスケープ攻撃による影響を抑えるため、権限のないユーザーとしてコンテナプロセスを実行すること |
| 読み取り専用ルート | ランタイム中の変更を防ぐため、コンテナのルートファイルシステムを読み取り専用でマウントすること |
| イメージダイジェスト | 特定のイメージバージョンを一意に識別する SHA256 ハッシュ。変更可能なタグよりも正確です |
| Scratch イメージ | OS を必要としない静的コンパイル済みバイナリに使用する、空の Docker ベースイメージ |
| セキュリティコンテキスト | 権限、ファイルシステム、ケイパビリティを制御する Kubernetes のポッド/コンテナレベルのセキュリティ設定 |
ツールとシステム
- Docker BuildKit:マルチステージビルドとビルドシークレットに対応する高度な Docker ビルドエンジン
- Distroless Images:Google の最小構成コンテナベースイメージ(static、base、java、python、nodejs)
- docker-bench-security:CIS Docker Benchmark への準拠をチェックするスクリプト
- Trivy:コンテナイメージの脆弱性および設定ミスをスキャンするツール
- Hadolint:ベストプラクティスを適用する Dockerfile リンター
よくあるシナリオ
シナリオ:1.2GB の Python イメージを 150MB 未満に縮小する
背景:あるデータサイエンスチームは、科学技術計算用のパッケージとともに、ベースイメージとして python:3.12(1.2GB)を使用しています。このイメージには、不要なシステムパッケージに起因する既知の CVE が 200 件以上あります。
アプローチ:
- ベースイメージを
python:3.12-slim-bookworm(150MB)に切り替え、必要なシステムライブラリのみをインストールする - マルチステージビルドを使用する。ビルダーステージで C 拡張機能をコンパイルし、wheel を本番環境にコピーする
- 本番環境でのビルド依存関係を避けるため、numpy、pandas、scipy をビルド済み wheel に固定する
- 最終イメージから pip、setuptools、wheel を削除する
- 非 root ユーザーを作成し、ファイルシステムの権限を設定する
- Trivy で検証する。CVE 数が 200 件以上から 20 件未満に減ることを見込む
注意点:一部の Python パッケージは、ランタイムに共有ライブラリ(libgomp、libstdc++)を必要とします。システムパッケージを削除した後は、アプリケーションを十分にテストしてください。Alpine ベースのイメージは musl libc を使用するため、numpy や pandas との互換性に問題が生じる可能性があります。
出力形式
Container Image Hardening Report
==================================
Image: app:hardened
Base: python:3.12-slim-bookworm
Date: 2026-02-23
SIZE COMPARISON:
Before hardening: 1,247 MB (python:3.12)
After hardening: 143 MB (python:3.12-slim + multi-stage)
Reduction: 88.5%
SECURITY CHECKS:
[PASS] Non-root user configured (appuser:1000)
[PASS] HEALTHCHECK instruction present
[PASS] No setuid/setgid binaries found
[PASS] Package manager removed
[PASS] Base image pinned by digest
[PASS] No shell access (/bin/sh removed)
[WARN] /tmp writable (emptyDir mounted)
VULNERABILITY COMPARISON:
Before: 234 CVEs (12 Critical, 45 High)
After: 18 CVEs (0 Critical, 3 High)
Reduction: 92.3%
コメント
Markdown 対応