Dockerコンテナセキュリティ:ベストプラクティスと脆弱性対策
安全なコンテナイメージの作り方、脆弱性スキャン、ランタイムセキュリティなど、コンテナ環境を守るための必須知識を解説。開発から本番運用までの各フェーズで実践すべきセキュリティ対策を網羅します。
佐藤 裕介
大規模サービスのインフラ運用経験10年以上。Kubernetes、Terraform、CI/CDパイプライン構築を得意とし、信頼性の高いシステム基盤を提供します。
なぜコンテナセキュリティが重要なのか?
Dockerをはじめとするコンテナ技術は、アプリケーションの開発とデプロイを劇的に効率化しました。しかし、その手軽さの裏で、新たなセキュリティリスクも生まれています。コンテナはホストOSのカーネルを共有するため、一度コンテナが侵害されると、ホストや他のコンテナへ被害が拡大する恐れがあります。
安全なコンテナ運用を実現するためには、開発ライフサイクルの各段階でセキュリティを考慮する「シフトレフト」のアプローチが不可欠です。
ライフサイクルで考えるコンテナセキュリティ
コンテナセキュリティは、単一のツールや設定で実現できるものではありません。「イメージ作成」→「CI/CDパイプライン」→「本番運用(ランタイム)」というライフサイクル全体で対策を講じる必要があります。
graph TD
A[開発者] --> B(Dockerfile作成);
B --> C{CI/CD パイプライン};
subgraph C
C1[1. イメージビルド] --> C2[2. 脆弱性スキャン];
C2 --> C3[3. レジストリへPush];
end
C3 --> D{コンテナレジストリ};
D --> E(本番環境へデプロイ);
subgraph E
E1[Kubernetes/ECS] --> E2(コンテナ実行);
end
F[監視] --> E2;
図: コンテナセキュリティのライフサイクル
1. Dockerfileのベストプラクティス (イメージ作成)
安全なコンテナ運用の第一歩は、セキュアなDockerfileを書くことから始まります。
a. 公式で軽量なベースイメージを使用する
ubuntuやdebianのような汎用的なOSイメージではなく、node:18-alpineやpython:3.10-slimのように、アプリケーションに必要な最小限のライブラリのみを含む公式の軽量イメージを使いましょう。これにより、攻撃対象領域(アタックサーフェス)を削減できます。
b. 非rootユーザーで実行する
コンテナ内でのプロセスをrootユーザーで実行するのは非常に危険です。コンテナが侵害された場合、ホストのroot権限を奪われる可能性があります。
FROM node:18-alpine
# 非rootユーザーとグループを作成
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
# 作業ディレクトリを作成し、所有者を設定
WORKDIR /app
COPY . .
RUN chown -R appuser:appgroup /app
# ユーザーを切り替え
USER appuser
CMD ["node", "index.js"]
c. マルチステージビルドを活用する
ビルド時にのみ必要なツール(コンパイラ、テストライブラリなど)を最終的なイメージに含めないように、マルチステージビルドを使いましょう。これにより、イメージサイズを削減し、不要な攻撃対象を排除できます。
# 1. ビルドステージ
FROM node:18 as builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# 2. 本番ステージ
FROM node:18-alpine
WORKDIR /app
# ビルドステージから成果物のみをコピー
COPY --from=builder /app/dist ./dist
COPY package*.json ./
RUN npm install --only=production
USER node
CMD ["node", "dist/index.js"]
d. COPYをADDより優先して使う
ADD命令は、リモートURLからのダウンロードやtarファイルの自動展開といった多機能さを持っていますが、これが予期せぬ挙動を引き起こす可能性があります。単純なファイルコピーにはCOPYを使いましょう。
2. 脆弱性スキャン (CI/CD)
作成したイメージに既知の脆弱性が含まれていないか、CI/CDパイプラインで自動的にスキャンすることが重要です。
- Trivy: Aqua Securityが開発したオープンソースの脆弱性スキャナ。OSパッケージとアプリケーションの依存関係の両方をスキャンでき、導入も簡単です。
- Snyk: 開発者向けのセキュリティプラットフォーム。コンテナイメージだけでなく、ソースコード、オープンソースライブラリの脆弱性も検出できます。
- Docker Scout: Docker HubやDocker Desktopに統合された脆弱性スキャン機能。
CIパイプラインにスキャンを組み込み、重大な脆弱性が検出された場合はビルドを失敗させることで、脆弱なイメージが本番環境にデプロイされるのを防ぎます。
# GitHub ActionsでのTrivyを使ったスキャンの例
jobs:
build_and_scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build the Docker image
run: docker build . --tag my-app:latest
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: 'my-app:latest'
format: 'table'
exit-code: '1' # 1に設定すると、脆弱性が見つかった場合にワークフローを失敗させる
ignore-unfixed: true
vuln-type: 'os,library'
severity: 'CRITICAL,HIGH'
3. ランタイムセキュリティ (本番運用)
本番環境でコンテナを実行する際には、以下の対策を講じることで、万が一コンテナが侵害された場合でも被害を最小限に抑えます。
a. 読み取り専用ファイルシステム
コンテナのファイルシステムを読み取り専用に設定し、攻撃者がコンテナ内に不正なファイルを書き込んだり、設定を改ざんしたりするのを防ぎます。アプリケーションが一時ファイルを書き込む必要がある場合は、tmpfsマウントを明示的に指定します。
b. Linuxカーネルのセキュリティ機能を活用する
- AppArmor / SELinux: プロセスがアクセスできるファイルやネットワークポートなどを制限する強制アクセス制御(MAC)システム。コンテナごとに専用のプロファイルを作成し、不要な権限を剥奪します。
- Seccomp: プロセスが発行できるシステムコールを制限する機能。コンテナが通常使用しない危険なシステムコール(
clone,mountなど)を禁止します。
c. ランタイム脅威検知
コンテナの実行中の不審な挙動(予期せぬプロセスの起動、不正なネットワーク接続、ファイルシステムの変更など)をリアルタイムで検知し、アラートを上げる仕組みです。
- Falco: CNCFのオープンソースプロジェクト。カーネルレベルのイベントを監視し、ルールに基づいて異常なアクティビティを検出します。
まとめ
Dockerコンテナのセキュリティは、特定の時点での対策だけでなく、開発から運用までのライフサイクル全体を通じた継続的な取り組みが求められます。
- Dockerfile:
root実行を避け、マルチステージビルドでイメージを最小化する。 - CI/CD: TrivyやSnykを導入し、脆弱性スキャンを自動化する。
- ランタイム: 読み取り専用ファイルシステムやSeccomp、Falcoなどを活用してコンテナを要塞化する。
これらのベストプラクティスを組織的に実践することで、コンテナ技術のメリットを安全に享受し、堅牢なアプリケーション基盤を構築することができます。
著者について
佐藤 裕介
大規模サービスのインフラ運用経験10年以上。Kubernetes、Terraform、CI/CDパイプライン構築を得意とし、信頼性の高いシステム基盤を提供します。