Docker: コンテナセキュリティのベストプラクティス

最終更新:2026-08-26

コンテナセキュリティはオプションではありません。イメージからランタイムまで、すべての層をハードニングする必要があります。

1. 学べること



2. セキュリティ監査の物語

(1) 悩み: 28 件のセキュリティ監査アラート

Charlie のチームにセキュリティ監査レポートが届きました。28 件のアラートのうち「コンテナが root として実行されている」(高リスク)、「イメージに高リスク CVE が 15 件含まれる」(高リスク)、「シークレットが環境変数に保存されている」(中リスク) などが挙がっていました。監査スコアはわずか 45。コンプライアンス達成のためには 80 以上へ引き上げる必要があります。

(2) 体系的なセキュリティハードニングへの取り組み

Charlie はチームを率いて、問題を一つずつ解決していきました。root 以外のユーザーへの変更、Trivy スキャンによる CVE 修正、Docker Secrets への切り替え、seccomp によるシステムコール制限を実施しました。

BASH
# セキュリティハードニング: root 以外 + 最小ケーパビリティ
docker run -d \
  --user 1000:1000 \
  --cap-drop ALL \
  --cap-add NET_BIND_SERVICE \
  --security-opt no-new-privileges \
  --read-only \
  myapp:1.0

(3) 結果: 監査スコア 45 → 92

体系的なハードニングを実施した結果、監査スコアは 45 から 92 へ向上し、すべての高リスク項目が解消されました。



3. コンテナセキュリティの階層モデル

(1) 階層化されたセキュリティ

100%
graph TB
    L6["6. シークレット管理<br/>Docker Secret / Vault"] --> L5["5. ネットワークセキュリティ<br/>ネットワーク分離 / TLS"]
    L5 --> L4["4. ランタイムセキュリティ<br/>seccomp / AppArmor / capabilities"]
    L4 --> L3["3. イメージセキュリティ<br/>スキャン / 署名 / 軽量化"]
    L3 --> L2["2. Docker デーモンセキュリティ<br/>TLS / ユーザー権限"]
    L2 --> L1["1. ホストセキュリティ<br/>OS 強化 / カーネル更新"]

(2) セキュリティレベルの比較

レベル ハードニング対策 効果
0 デフォルト設定 ❌ アラート多数
1 root 以外 + 最新タグ ⚠️ 基本的なセキュリティ
2 + イメージスキャン + バージョン固定 ✅ 中程度のセキュリティ
3 + 最小ケーパビリティ + seccomp ✅ 良好なセキュリティ
4 + DCT + シークレット管理 ✅ 高いセキュリティ
5 + ネットワーク分離 + 監査ログ ✅ 最大限のセキュリティ


4. イメージの脆弱性スキャン

▶ サンプル: Trivy によるイメージスキャン (難易度: ⭐⭐)

BASH
# Trivy をインストール (Linux)
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh

# イメージの脆弱性をスキャン
trivy image nginx:1.25-alpine

# 深刻度でフィルタしてスキャン
trivy image --severity HIGH,CRITICAL nginx:1.25-alpine

# JSON で出力してスキャン
trivy image --format json --output report.json myapp:1.0
💻 出力 (抜粋):

TEXT 📖 参照専用
nginx:1.25-alpine (alpine 3.19.0)
=========================
Total: 5 (HIGH: 2, CRITICAL: 0)

┌──────────┬────────────┬──────────┬──────────┬─────────────────┐
│ Library  │ Vulnerability│ Severity │ Version  │ Fixed Version   │
├──────────┼────────────┼──────────┼──────────┼─────────────────┤
│ libcurl  │ CVE-2023-xxxx│ HIGH     │ 8.4.0    │ 8.5.0           │
│ openssl  │ CVE-2023-yyyy│ HIGH     │ 3.1.3    │ 3.1.4           │
└──────────┴────────────┴──────────┴──────────┴─────────────────┘

▶ サンプル: Docker Scout スキャン (難易度: ⭐⭐)

BASH
# Docker Scout (Docker Desktop 内蔵)
docker scout quickview nginx:latest

# 詳細な CVE レポート
docker scout cves nginx:latest

# 2 つのイメージを比較
docker scout compare --from nginx:1.24 --to nginx:1.25


5. 最小権限の原則

(1) Linux ケーパビリティ

ケーパビリティ 機能 よく使われる用途
NET_BIND_SERVICE 1024 未満のポートへバインド Web サービス (80/443)
NET_RAW RAW ネットワークパケット ping / ネットワークデバッグ
CHOWN ファイルオーナーの変更 ファイル管理
SETUID / SETGID ユーザー切り替え 一部のシステムツール
ALL すべての権限 ❌ 使用しないこと

▶ サンプル: --cap-drop で最小権限を実現 (難易度 ⭐⭐⭐)

BASH
# すべてのケーパビリティを削除し、必要なものだけ追加する
docker run -d \
  --name secure-app \
  --cap-drop ALL \
  --cap-add NET_BIND_SERVICE \
  --security-opt no-new-privileges \
  -p 80:8080 \
  myapp:1.0
パラメータ 機能
--cap-drop ALL すべての Linux ケーパビリティを削除
--cap-add NET_BIND_SERVICE 低ポートへのバインド権限のみを追加
--security-opt no-new-privileges 権限昇格を禁止 (setuid / setgid)
--read-only 読み取り専用ファイルシステム (tmpfs が必要)
🔒 セキュリティ: --privileged はコンテナにホストのほぼすべての権限を付与します。本番環境では絶対に使用しないでください。--cap-drop ALL + 必要に応じた --cap-add の組み合わせが、最小権限の原則の体現です。**



6. ランタイムセキュリティ

▶ サンプル: seccomp でシステムコールを制限 (難易度: ⭐⭐⭐)

BASH
# カスタム seccomp プロファイルで実行
docker run -d \
  --security-opt seccomp=chrome.json \
  --name browser \
  chromium:latest

(1) Docker デフォルトの seccomp

Docker にはデフォルトの seccomp 設定ファイルが付属しており、mountkeyctladd_key など約 44 個の危険なシステムコールを無効化しています。多くのアプリケーションはデフォルト設定で正常に動作します。

▶ サンプル: Docker Content Trust による署名 (難易度: ⭐⭐)

BASH
# 現在のセッションで DCT を有効化
export DOCKER_CONTENT_TRUST=1

# 署名済みイメージをプッシュ
docker push myorg/myapp:v1.0

# プル時: DCT が署名を検証
docker pull myorg/myapp:v1.0

# 署名されていないイメージのプル: 拒否される (DCT が有効な場合)
docker pull myorg/myapp:unsigned
# Error: No trust data for unsigned


7. シークレットの安全な管理

(1) 3 つのシークレット管理手法の比較

手法 セキュリティレベル 可視性 適用シーン
環境変数 (-e) ❌ 低 docker inspect で可視 開発環境
ボリュームファイル (-v) ⚠️ 中 ホストファイルから可視 移行計画
Docker Secret ✅ 高 暗号化保存 + ランタイムマウント Swarm 本番環境
外部 Vault ✅ 最高 一元管理 + 監査 エンタープライズ向け


8. CIS Docker Benchmark

▶ サンプル: Docker Bench Security ベースラインチェック (難易度: ⭐⭐)

BASH
# CIS Docker Benchmark チェックを実行
docker run --rm --net host --pid host \
  --userns host --cap-drop audit_control \
  -e DOCKER_CONTENT_TRUST=$DOCKER_CONTENT_TRUST \
  -v /etc:/etc:ro \
  -v /lib/systemd/system:/lib/systemd/system:ro \
  -v /usr/bin/containerd:/usr/bin/containerd:ro \
  -v /usr/bin/runc:/usr/bin/runc:ro \
  -v /usr/lib/systemd:/usr/lib/systemd:ro \
  -v /var/lib:/var/lib:ro \
  -v /var/run/docker.sock:/var/run/docker.sock:ro \
  docker/docker-bench-security
💻 出力 (抜粋):

TEXT 📖 参照専用
[INFO] 1 - Host Configuration
[INFO] 1.1  - Ensure Docker is up to date
[PASS] 1.2  - Ensure only trusted users are allowed to control Docker daemon
[WARN] 1.4  - Ensure a separate partition for containers has been created

[INFO] 4 - Container Images
[PASS] 4.1  - Ensure a user for the container has been created
[WARN] 4.7  - Ensure HEALTHCHECK instructions have been added
[WARN] 4.9  - Ensure COPY is used instead of ADD


9. 完全なサンプル: 本番コンテナのフルスタックハードニング

BASH
# ============================================
# 完全な手順: 本番コンテナのハードニング
# 監査スコア 45 → 92 を実現
# ============================================

# ステップ 1: 脆弱性をスキャン
trivy image --severity HIGH,CRITICAL myapp:1.0
# 対策: ベースイメージを更新し、バージョンを固定する

# ステップ 2: 最大限のセキュリティ制約で実行
docker run -d \
  --name hardened-app \
  --user 1000:1000 \
  --cap-drop ALL \
  --cap-add NET_BIND_SERVICE \
  --security-opt no-new-privileges \
  --security-opt seccomp=default.json \
  --read-only \
  --tmpfs /tmp:rw,noexec,nosuid \
  --tmpfs /run:rw,noexec,nosuid \
  -v app-logs:/app/logs \
  --log-driver json-file \
  --log-opt max-size=10m \
  --log-opt max-file=3 \
  --health-cmd="curl -f http://localhost:8080/health || exit 1" \
  --health-interval=30s \
  --health-retries=3 \
  -p 8080:8080 \
  myapp:hardened

# ステップ 3: セキュリティ設定を検証
docker inspect hardened-app --format='
User: {{.Config.User}}
ReadOnly: {{.HostConfig.ReadonlyRootfs}}
Capabilities: {{.HostConfig.CapAdd}}
NoNewPrivileges: {{.HostConfig.SecurityOpt}}
'

# ステップ 4: CIS ベンチマークを実行
docker run --rm ... docker/docker-bench-security

# ステップ 5: ハードニング後に再スキャン
trivy image myapp:hardened

❓ よくある質問

Q Docker コンテナは完全に隔離できますか?
A いいえ、完全には隔離できません。コンテナはホストのカーネルを共有しているため、カーネルの脆弱性がコンテナエスケープにつながる可能性があります。ただし、コンテナはプロセスレベルの隔離 (namespace + cgroup + seccomp + AppArmor) を提供し、攻撃対象領域を大幅に縮小します。重要なポイント: --privileged オプションを使用しない、root として実行しない、カーネルを迅速にアップデートする、です。
Q --privileged を使うとどのようなリスクがありますか?
A --privileged はコンテナにホストのほぼすべての権限を付与します。すべてのデバイスへのアクセス、カーネルパラメータの変更、カーネルモジュールのロード、seccomp / AppArmor のバイパスなどが可能になります。これは実質的にホスト上で直接プログラムを実行するのと同じです。本番環境では --privileged を絶対に使用しないでください。
Q イメージの脆弱性スキャンにはどのツールを使えばよいですか?
A Trivy (オープンソース、最も人気) または Docker Scout (Docker Desktop に内蔵) を使用してください。CI/CD への統合が鍵です: ビルド後に自動スキャンを実行し、CRITICAL レベルの脆弱性が検出された場合はデプロイをブロックします。本番イメージは毎日スキャンし、新たな CVE が公開され次第、速やかにリビルドすることをおすすめします。
Q 環境変数にシークレットを保存することの何が問題ですか?
A 3 つのリスクがあります。① docker inspect で環境変数が誰でも閲覧可能になる。② 子プロセスが環境変数を継承する。③ 環境変数が誤ってログに出力される可能性がある。Docker Secrets (Swarm) は暗号化された形で保存され、ランタイムでは一時ファイルとしてマウントされるためより安全です。Swarm 以外の環境では HashiCorp Vault を使用してください。
Q Rootless モードは安全ですか?
A 非常に安全です。Rootless Docker は Docker デーモン全体を一般ユーザーとして実行するため、Docker 自体に脆弱性があっても、攻撃者が得られるのは一般ユーザーの権限だけです。ただし、Rootless モードにはいくつかの制限があります (--privileged オプションが使えない、ネットワーク構成に制約がある)。本番環境には Rootless モードを推奨します。

📖 まとめ


📝 練習問題

  1. 基礎問題 (難易度: ⭐): ローカルマシンで Docker Bench Security スキャンを実行し、WARN レベルのアラートを記録してください。
  2. 応用問題 (難易度 ⭐⭐): Trivy を使って既存イメージをスキャンし、すべての CRITICAL レベルの CVE を修正してください。
  3. 挑戦問題 (難易度: ⭐⭐⭐): seccomp で制限をかけたコンテナを作成し、mount システムコールを無効化するなどして、制限が効いていることを検証してください。
Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%