Dockerの導入により、開発とデプロイのスピードは飛躍的に向上しました。しかし、便利さの反面、適切に設定されていないコンテナはセキュリティ上の大きなリスクを抱えることになります。
「コンテナは隔離されているから安全」という考えは非常に危険です。悪意のある攻撃者がコンテナを突破し、ホストOS(サーバー本体)を制御する「コンテナ脱出(Container Breakout)」といった攻撃手法も存在します。
本記事では、Docker運用において必須となるセキュリティ・ベストプラクティスを解説し、実際に手を動かして脆弱なコンテナを「要塞化」するハンズオンをお届けします。
1. Dockerセキュリティの主要なリスクとは?
Dockerセキュリティを考える上で、守るべきレイヤーは大きく分けて3つあります。
- イメージの安全性: ベースイメージ自体に脆弱性が含まれていないか?
- 実行時の制御: コンテナが必要以上の権限(特権)を持っていないか?
- ホストOSの保護: コンテナがホストの重要なリソースにアクセスできないか?
なぜ「rootユーザー」のまま実行するのが危険なのか?
デフォルト設定では、Dockerコンテナ内のプロセスは多くの場合 root(管理者)権限 で実行されます。もしアプリケーションに脆弱性があり、攻撃者がリモートからコードを実行できた場合、コンテナ内のroot権限を奪取され、さらにホストOSの脆弱性を突いてサーバー全体を支配されるリスクがあります。
2. 実践ハンズオン:脆弱なコンテナの要塞化
ここでは、あえて「危険な設定」のコンテナを作成し、それを一つずつ修正して安全な状態(Hardening)にしていきます。
2-1. プロジェクトの準備
以下のフォルダ構成でファイルを作成します。
/docker_security_lab
├── Dockerfile.vulnerable # 脆弱な設定
├── Dockerfile.secure # 修正後の安全な設定
└── app.py
2-2. 脆弱なDockerfileの確認
まずは、やってはいけない「アンチパターン」が詰まったDockerfileを見てみましょう。
Dockerfile
# Dockerfile.vulnerable
# 1. 非常に重く、不要なツールが多いベースイメージ
FROM python:3.10
# 2. 作業ディレクトリをルートにするのは危険
WORKDIR /
COPY . .
# 3. 依存関係のインストール時に権限を考慮しない
RUN pip install flask
# 4. デフォルトの root ユーザーのまま実行(非常に危険!)
CMD ["python", "app.py"]
2-3. セキュリティを強化したDockerfile(要塞化)
次に、ベストプラクティスを適用したDockerfileを作成します。
Dockerfile
# Dockerfile.secure
# 1. 最小限のベースイメージ (alpineやslim) を使用し、攻撃表面を減らす
FROM python:3.10-slim
# 2. アプリケーション専用のユーザーを作成し、root権限を捨てる
# --system: システムユーザーとして作成, --no-create-home: ホームディレクトリを作らない
RUN groupadd -r appuser && useradd -r -g appuser appuser
# 3. 作業ディレクトリを適切に設定
WORKDIR /app
# 4. 依存関係のインストール(rootで行い、キャッシュを利用)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 5. アプリケーションコードをコピーし、所有者を変更
COPY --chown=appuser:appuser . .
# 6. 作成した非rootユーザーに切り替え
USER appuser
# 7. コンテナの読み取り専用属性を補助(アプリによる書き込みを制限)
# 実行時のコマンドで --read-only を指定するのが一般的
CMD ["python", "app.py"]
3. Docker実行時のセキュリティ・フラグ
Dockerfileの記述だけでなく、コンテナ起動時のオプション(docker run や docker-compose)でもセキュリティを強化できます。
3-1. リソース制限(DoS攻撃対策)
1つのコンテナがホストのメモリやCPUを使い果たすと、他のサービスが停止します。
Bash
# メモリを512MB、CPUを0.5個分に制限して起動
docker run -d \
--name secure-app \
--memory="512m" \
--cpus="0.5" \
my-secure-image
3-2. ファイルシステムの読み取り専用化
攻撃者がコンテナ内にマルウェアをダウンロードしたり、設定ファイルを書き換えたりするのを防ぎます。
Bash
# ルートファイルシステムを読み取り専用にする
# 書き込みが必要な場所(一時フォルダなど)だけ tmpfs で許可
docker run -d \
--read-only \
--tmpfs /tmp \
my-secure-image
3-3. 権限(Capabilities)の最小化
Linuxカーネルの特権を、必要最低限のみコンテナに与えます。
Bash
# 全ての権限を一度捨て(drop)、必要なものだけを追加(add)
docker run -d \
--cap-drop=ALL \
--cap-add=NET_BIND_SERVICE \
my-secure-image
4. 脆弱性スキャンツールの導入
イメージがビルドされた後に、既知の脆弱性(CVE)が含まれていないかチェックすることが不可欠です。
おすすめのツールは、Trivy (by Aqua Security) です。
スキャンの実行例:
Bash
# ローカルのイメージをスキャン
trivy image my-secure-image:latest
これにより、OSパッケージやPythonライブラリ内のセキュリティホールを即座に特定できます。
5. セキュリティチェックリスト
本番環境にデプロイする前に、以下の項目を確認してください。
| 項目 | 対策内容 |
| ベースイメージ | 信頼できる公式イメージの「slim」や「alpine」版を使っているか? |
| ユーザー権限 | コンテナ内で USER 指定を行い、非rootで動作させているか? |
| リソース制限 | CPUやメモリの制限値が設定されているか? |
| 読み取り専用 | 可能であれば --read-only を使用しているか? |
| スキャン | Trivy等でビルドごとに脆弱性検査を行っているか? |
| シークレット管理 | パスワードやAPIキーを ENV で渡さず、Docker Secretsや環境変数ファイルを利用しているか? |
【内部リンク】 環境変数の安全な管理方法については、「Docker Composeでの機密情報管理:.envとSecretsの使い分け」で詳しく解説しています。
まとめ
Dockerセキュリティは「一度設定すれば終わり」ではありません。ベースイメージの更新や定期的な脆弱性スキャン、最小権限原則の徹底が必要です。
「安全なコンテナは、小さなベースイメージと最小限の権限から生まれる」という原則を忘れずに、セキュアな開発ライフを実現しましょう!
【外部リンク】 より高度なセキュリティ設定については、Docker公式セキュリティドキュメントおよびCIS Docker Benchmarkを強く推奨します。
コメントを残す