はじめに
Dockerfile でビルドコンテキストを過剰にコピーすると、ビルドシークレットがイメージ内に漏洩する可能性があります。よくある間違いは COPY . /app/ です。これは便利ですが、トークン、認証情報、ローカルのメモ、一時ファイルなどが最終的なイメージに含まれてしまうリスクがあります。一度シークレットがイメージレイヤーに入り込んでしまうと、実行時の制御でこのサプライチェーン上のミスを確実に取り消すことはできません。
この実験では、意図的にシークレットが漏洩するローカルイメージをビルドし、ステージング用のビルドトークンがイメージ内に存在することを証明します。その後、Dockerfile のコピー範囲を絞り込み、.dockerignore を追加することでビルドプロセスを修正します。最後に、クリーンなイメージをデプロイし、実行中のコンテナにビルドシークレットが含まれていないことを検証します。
不安全なビルドコンテキストの調査
このステップでは、ビルドコンテキストと不安全な Dockerfile を調査します。ビルドコンテキストとは、イメージビルダーに送信されるディレクトリのことです。Dockerfile がコンテキスト全体をコピーすると、そのディレクトリ内のすべてのファイルが最終的なイメージの一部になる可能性があります。
実験ワークスペースで開始します:
cd /home/labex/project/build-secret-image
メモを読みます:
sed -n '1,120p' BUILD_SECRET_NOTES.md
現在ビルドコンテキストに存在するファイルの一覧を表示します:
find . -maxdepth 1 -type f -printf '%f\n' | sort | tee evidence/initial-context-files.txt
不安全な Dockerfile を確認します:
sed -n '1,120p' Dockerfile.insecure | tee evidence/insecure-dockerfile-review.txt
リスクのある行は COPY . /app/ です。これは app.sh をコピーしますが、同時に build-token.txt もコピーしてしまいます。次のステップでは、このイメージをビルドし、イメージの実行環境内から漏洩を証明します。
漏洩するイメージのビルドとシークレットの存在確認
このステップでは、labex-v134 minikube プロファイル内で不安全なイメージをビルドします。プロファイル内でビルドすることで、Kubernetes ノードのランタイムからイメージが見えるようになります。
不安全な Dockerfile をアクティブな Dockerfile 名にコピーし、漏洩するイメージをビルドします:
cp Dockerfile.insecure Dockerfile
minikube -p labex-v134 image build -t labex/leaky-build:1.0 .
minikube の Docker ランタイム内でイメージを実行し、トークンファイルを確認します:
minikube -p labex-v134 ssh -- 'docker run --rm --entrypoint /bin/sh labex/leaky-build:1.0 -c "ls -l /app && cat /app/build-token.txt"' | tee evidence/leaky-image-contents.txt
build-token=labex-temporary-secret が表示されるはずです。これが漏洩です。イメージは実行されますが、本来は最終的なランタイムイメージの外にあるべきファイルが含まれてしまっています。
コピー境界を絞り込んだクリーンなイメージのビルド
このステップでは、イメージのビルドを修正します。重要な変更点は 2 つです。.dockerignore を使用してトークンがビルダーに送信されるビルドコンテキストに入らないようにし、Dockerfile ではディレクトリ全体ではなく app.sh のみをコピーするようにします。
.dockerignore を作成します:
cat > .dockerignore <<'EOF'
build-token.txt
evidence/
*.txt
EOF
クリーンな Dockerfile を作成します:
cat > Dockerfile <<'EOF'
FROM busybox:1.36
WORKDIR /app
COPY app.sh /app/app.sh
RUN chmod 0555 /app/app.sh
USER 65534:65534
ENTRYPOINT ["/app/app.sh"]
EOF
クリーンなイメージをビルドします:
minikube -p labex-v134 image build -t labex/clean-build:1.0 .
minikube の Docker ランタイム内からクリーンなイメージを調査します:
minikube -p labex-v134 ssh -- 'docker run --rm --entrypoint /bin/sh labex/clean-build:1.0 -c "ls -l /app; if [ -f /app/build-token.txt ]; then echo BUILD_SECRET_PRESENT; else echo NO_BUILD_SECRET; fi; id -u"' | tee evidence/clean-image-contents.txt
出力には NO_BUILD_SECRET と UID 65534 が表示されるはずです。
クリーンなイメージのデプロイ
このステップでは、クリーンなイメージをデプロイし、実行中のコンテナでビルドシークレットが存在しないことを確認します。これにより、イメージが実際に実行される Kubernetes 環境に近い状態で最終的な証明を行います。
Pod マニフェストを作成して適用します:
cat > clean-build-pod.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: clean-build-app
namespace: cks-prep-build-secret
labels:
app: clean-build-app
spec:
restartPolicy: Never
containers:
- name: app
image: labex/clean-build:1.0
imagePullPolicy: Never
securityContext:
runAsNonRoot: true
runAsUser: 65534
runAsGroup: 65534
allowPrivilegeEscalation: false
EOF
kubectl apply -f clean-build-pod.yaml
Pod が準備完了になるのを待ち、ログを読み取ります:
kubectl -n cks-prep-build-secret wait --for=condition=Ready pod/clean-build-app --timeout=120s
kubectl -n cks-prep-build-secret logs clean-build-app | tee evidence/clean-pod-logs.txt
ログには以下が含まれているはずです:
clean build image ready
NO_BUILD_SECRET
まとめ
不安全なイメージのビルドコンテキストを調査し、漏洩するイメージをビルドしてビルドトークンの存在を証明した後、.dockerignore と Dockerfile の COPY 命令を絞り込むことでビルドを修正しました。非 root ユーザーとして実行され、NO_BUILD_SECRET を報告するクリーンなイメージをビルドおよびデプロイしました。これにより、イメージビルドの衛生管理と Kubernetes ランタイムの検証を結びつけ、サプライチェーンのステージを完了しました。



