イメージに残るビルド時の秘密
次の Dockerfile でビルドしたコンテナイメージを顧客に配布する。NPM_TOKEN は社内レジストリのアクセストークンで,ビルド時に --build-arg で渡している。
FROM node:lts-slim
ARG NPM_TOKEN
WORKDIR /app
COPY package.json package-lock.json ./
RUN echo "registry=https://npm.example.com/" > .npmrc \
&& echo "//npm.example.com/:_authToken=${NPM_TOKEN}" >> .npmrc
RUN npm ci --omit=dev
RUN rm -f .npmrc
COPY src/ ./src/
USER node
CMD ["node", "src/server.js"]このイメージに関する記述として,適切なものはどれか。
- ア.npmrc は後の RUN 命令で削除しているが,トークンを書き込んだ RUN 命令のレイヤに残っているので,イメージを入手した者はレイヤを展開してトークンを取り出せる。
- イコンテナ内のプロセスは root 権限で動作するので,アプリケーションの脆弱性を突かれると,コンテナ内の全てのファイルを改ざんされるおそれがある。
- ウARG 命令で受け取ったビルド引数の値は,ビルド中の命令からだけ参照でき,イメージの履歴やメタデータには記録されないので,ビルド引数の値はイメージから取り出せない。
- エマルチステージビルドに変更しても,最終ステージのイメージには前のステージの全てのレイヤが含まれるので,トークンの漏えいを防ぐ効果はない。
正解と解説を見る
正解 ア
この問題の基礎知識
- コンテナイメージは,Dockerfile の RUN や COPY などファイルシステムを変更する命令ごとに作られる読取り専用のレイヤを積み重ねたものであり,後の命令でファイルを削除しても,前のレイヤにはそのファイルが残る。
- ビルド引数(ARG)の値は docker history などで参照できることがあるので,秘密の受渡しには使わず,ビルド時のシークレットマウントなどレイヤに残らない方法を使う。
- マルチステージビルドでは,最終ステージを別のベースイメージから始め,前のステージから必要な成果物だけをコピーすれば,それ以外のものは最終イメージに含まれない。
- USER 命令は,それ以降の RUN 命令と,コンテナで動作するプロセス(CMD や ENTRYPOINT)を実行するユーザを指定する。
ア.npmrc は後の RUN 命令で削除しているが,トークンを書き込んだ RUN 命令のレイヤに残っているので,イメージを入手した者はレイヤを展開してトークンを取り出せる。正解
イメージの各レイヤは一度作られると変更されず,後のレイヤは削除したという変更を記録するだけである。トークンを書き込んだ RUN 命令のレイヤには .npmrc が残るので,秘密はビルド時のシークレットマウントで渡し,レイヤに書き込まないようにすべきである。
イコンテナ内のプロセスは root 権限で動作するので,アプリケーションの脆弱性を突かれると,コンテナ内の全てのファイルを改ざんされるおそれがある。
Dockerfile の終盤で USER node を指定しているので,CMD のプロセスは root ではない一般ユーザの node で動作する。USER の行を読み落とすと選んでしまう記述である。
ウARG 命令で受け取ったビルド引数の値は,ビルド中の命令からだけ参照でき,イメージの履歴やメタデータには記録されないので,ビルド引数の値はイメージから取り出せない。
ARG の値はそのままではコンテナの環境変数として残らないが,ビルド引数は docker history コマンドで参照できる。Docker の文書も,ビルド引数は最終イメージに残り docker history などで見えるので,秘密の受渡しに使うべきではないとしている。
エマルチステージビルドに変更しても,最終ステージのイメージには前のステージの全てのレイヤが含まれるので,トークンの漏えいを防ぐ効果はない。
マルチステージビルドでは,前のステージから必要な成果物だけを最終ステージにコピーでき,それ以外は最終イメージに含まれない。トークンを使う処理を前のステージに閉じ込めれば,配布するイメージには残らない。
検証用の出典出典照合済み
Docker Docs: Build secrets / Docker Docs: Dockerfile reference(ARG,USER) / Docker Docs: Multi-stage builds照合の根拠(6 件)
- ア(正解): 後の RUN の削除は変更として記録されるだけで,.npmrc を書き込んだレイヤは残る
Each layer in an image contains a set of filesystem changes - additions, deletions, or modifications.
Docker Docs: Understanding the image layers · Image layers(新しいタブで開きます) - ア(正解): レイヤは一度作られると変更されない
And each of these layers, once created, are immutable.
Docker Docs: Understanding the image layers · Image layers(新しいタブで開きます) - イ(誤り): USER node 指定後の CMD は node ユーザで動作する
The specified user is used for `RUN` instructions and at runtime runs the relevant `ENTRYPOINT` and `CMD` commands.
Dockerfile reference · USER(新しいタブで開きます) - ウ(誤り): ビルド引数は docker history で見えるので秘密の受渡しに使うべきではない
It isn't recommended to use build arguments for passing secrets such as > user credentials, API tokens, etc. Build arguments are visible in the > `docker history` command
Dockerfile reference · ARG(新しいタブで開きます) - ウ(誤り): ビルド引数は最終イメージに残る
Build arguments and environment variables are inappropriate for passing secrets to your build, because they persist in the final image.
Docker Docs: Build secrets · Introduction(新しいタブで開きます) - エ(誤り): マルチステージビルドでは必要な成果物だけを最終ステージにコピーし,それ以外は最終イメージに残さない
You can selectively copy artifacts from one stage to another, leaving behind everything you don't want in the final image.
Docker Docs: Multi-stage builds · Introduction(新しいタブで開きます)