脆弱な Docker イメージを作らないための設計とハンズオン

はじめに

Docker は開発効率を劇的に向上させる一方で、
Dockerfile の書き方次第では深刻なセキュリティリスクを抱える技術でもあります。

特に以下のようなケースは、実務現場で非常によく見られます。

  • 開発用 Dockerfile をそのまま本番で使用している
  • root 権限でアプリケーションが動作している
  • 知らないうちに secrets(APIキーなど)をイメージに含めている
  • ベースイメージの脆弱性を放置している

Dockerfile は単なる設定ファイルではなく、
「どの権限で」「どのライブラリを使い」「どの状態で」アプリを動かすかを決めるセキュリティ設計書です。

本記事では、Dockerfile に潜むリスクを整理したうえで、
安全な Docker イメージを作るための具体的な設計・ハンズオンを通して、
「なぜこの書き方が安全なのか」を理解できることを目指します。


Dockerfile が攻撃対象になる理由

Docker コンテナは「軽量な仮想環境」として認識されがちですが、
完全に隔離された安全な箱ではありません

Dockerfile 由来の代表的なリスク

  • root 権限での侵入による被害拡大
  • OS・ミドルウェアの既知脆弱性の悪用
  • 不要なツールを踏み台にした攻撃
  • イメージから secrets が流出

特に Dockerfile は一度イメージを作成すると、
誰がどこで使っても同じ内容が配布されるため、
ミスがそのまま横展開される危険性があります。

つまり Dockerfile の安全性 = 配布されるすべての環境の安全性 です。


Dockerfile セキュリティの基本原則

原則①:最小権限の原則(Least Privilege)

Dockerfile では、特に root ユーザー実行が問題になります。

root で動作するコンテナに侵入されると、

  • ファイル改ざん
  • 不正コマンド実行
  • 他コンテナへの攻撃

などに直結します。

「root で動かす理由がないなら、必ず避ける」
これが Dockerfile セキュリティの第一歩です。


原則②:最小構成(Minimal Image)

イメージに含まれるものが多いほど、

  • 脆弱性を含む可能性が高まる
  • 攻撃に使えるツールが増える
  • イメージサイズが肥大化する

という問題が発生します。

Dockerfile では
「本番実行に必要なものだけを含める」
という意識が重要です。


原則③:秘密情報を焼き込まない

Dockerfile やイメージに含めた secrets は、

  • Git 管理
  • イメージ共有
  • docker inspect

などを通じて、非常に簡単に漏洩します。

Dockerfile に secrets を書いた時点で事故は起きている

と考えるのが安全です。


危険な Dockerfile の典型例

FROM ubuntu:latest

RUN apt update && apt install -y curl vim git

WORKDIR /app
COPY . /app

CMD ["node", "index.js"]

なぜ危険なのか?

  • latest による不透明なバージョン管理
  • root 権限での実行
  • 不要なツール(vim, git, curl)
  • Node.js 実行環境が曖昧
  • 攻撃対象領域が非常に広い

この Dockerfile は
「動くかもしれないが、安全とは言えない」
典型的なアンチパターンです。


セキュアな Dockerfile の設計例

FROM node:20-alpine

WORKDIR /app

COPY package.json ./
RUN npm install --only=production

COPY . .

USER node

EXPOSE 3000
CMD ["node", "index.js"]

セキュリティ観点での改善点

  • OS を Alpine に限定し最小化
  • 依存関係を production のみに制限
  • 非 root ユーザーでの実行
  • 明示的なバージョン指定

「何が入っていて、何が入っていないかが明確」
これが安全な Dockerfile の特徴です。


ハンズオン①:root 実行のリスクを体感する

root 実行の Dockerfile

FROM node:20
WORKDIR /app
COPY . .
CMD ["node", "index.js"]

コンテナ内で確認します。

docker run -it image-name sh
whoami
root

この状態で侵入されると、
アプリケーションの権限を超えた操作が可能になります。


ハンズオン②:非 root ユーザーで実行する

FROM node:20-alpine

WORKDIR /app

COPY package.json ./
RUN npm install --only=production

COPY . .

USER node
CMD ["node", "index.js"]
whoami
node

被害がコンテナ内の限定的な範囲に抑えられる
これが非 root 実行の最大のメリットです。


secrets を Dockerfile に書いてはいけない理由

ENV API_KEY=xxxxx

この値は、

  • イメージ履歴
  • docker inspect
  • レジストリ経由

で誰でも取得できます。

正しい考え方

  • Dockerfile:構造を定義
  • 実行時:機密情報を注入
docker run -e API_KEY=xxxxx app

マルチステージビルドによる攻撃面削減

マルチステージビルドは
セキュリティとパフォーマンスを同時に改善します。

FROM node:20 AS build
WORKDIR /app
COPY . .
RUN npm install && npm run build

FROM node:20-alpine
WORKDIR /app
COPY --from=build /app/dist ./dist
USER node
CMD ["node", "dist/index.js"]

得られる効果

  • ビルド用ツールを本番から排除
  • イメージサイズ削減
  • 脆弱性混入リスク低下

Dockerfile セキュリティチェックリスト

  • latest タグを使っていない
  • 非 root ユーザーで動作している
  • secrets を含んでいない
  • 不要なツールを含めていない
  • .dockerignore を設定している
  • マルチステージを検討している

まとめ

Dockerfile のセキュリティは、

  • 特別なツールより 設計意識が重要
  • 小さな選択が大きな事故を防ぐ
  • 本番運用では必須のスキル

です。


投稿日

カテゴリー:

投稿者:

コメント

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です