⑥Docker・コンテナ

Dockerのセキュリティベストプラクティス【本番運用前に必ず確認】

⑥Docker・コンテナ
記事内に広告が含まれています。

Dockerはアプリケーション開発・運用の効率を大幅に向上させる強力なツールですが、セキュリティ設定を怠ると重大なリスクを招く可能性があります。この記事では、Docker環境を本番運用する前に必ず確認しておくべきセキュリティベストプラクティスを徹底解説します。

① rootユーザーでコンテナを実行しない

Dockerコンテナはデフォルトでrootユーザーとして実行されます。コンテナ内でrootとして動くプロセスは、コンテナが侵害された場合にホストへの攻撃経路になり得ます。必ず専用の非rootユーザーを作成して実行しましょう。

# Dockerfileで非rootユーザーを指定する例
FROM ubuntu:22.04

# 専用ユーザーを作成
RUN groupadd -r appuser && useradd -r -g appuser appuser

# アプリをコピー
COPY app.py /app/app.py
WORKDIR /app

# 所有権を変更
RUN chown -R appuser:appuser /app

# 非rootユーザーで実行
USER appuser

CMD ["python3", "app.py"]

docker runコマンドで実行時に指定することも可能です。

# UID 1000のユーザーとして実行
docker run --user 1000:1000 myimage

② 信頼できるベースイメージだけを使う

Docker Hubには悪意あるイメージが混入しているケースもあります。以下のルールを守りましょう。

  • 公式イメージ(Official Image)を優先して使う(ubuntu、python、nginx など)
  • イメージには具体的なタグを指定する(python:3.11-slimのように。:latestは避ける)
  • プライベートレジストリを構築して社内で管理されたイメージを使う
  • イメージのダイジェスト(SHA256)を固定して改ざんを防ぐ
# タグを明示的に指定(latestは避ける)
FROM python:3.11.9-slim

# ダイジェストで固定する場合
FROM python@sha256:abc123...

③ イメージを軽量・最小限に保つ

イメージに不要なツールやパッケージが含まれていると、攻撃面積(アタックサーフェス)が広がります。

  • alpineslimバリアントなど最小限のベースイメージを使う
  • マルチステージビルドでビルドツールを最終イメージに含めない
  • apt-getの後はrm -rf /var/lib/apt/lists/*でキャッシュを削除する
# マルチステージビルドの例
# ステージ1:ビルド環境
FROM golang:1.21 AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp

# ステージ2:実行環境(最小限)
FROM alpine:3.19
COPY --from=builder /app/myapp /usr/local/bin/myapp
CMD ["myapp"]

④ 機密情報をイメージに含めない

パスワードやAPIキーをDockerfileやイメージに直接書くのは絶対に避けましょう。イメージをpushした時点で誰でも見られる状態になります。

環境変数を使う

# docker run時に環境変数を渡す
docker run -e DB_PASSWORD=secret myimage

# .envファイルを使う(.gitignoreに追加すること)
docker run --env-file .env myimage

Docker Secretsを使う(Swarm環境)

# シークレットを作成
echo "mysecretpassword" | docker secret create db_password -

# docker-compose.ymlでシークレットを参照
services:
  db:
    image: postgres
    secrets:
      - db_password

secrets:
  db_password:
    external: true

⑤ コンテナのケーパビリティを制限する

DockerコンテナはデフォルトでいくつかのLinuxケーパビリティ(権限)を持っています。不要なケーパビリティは削除し、最小限の権限で動かしましょう。

# 全ケーパビリティを削除してから必要なものだけ追加
docker run --cap-drop ALL --cap-add NET_BIND_SERVICE myimage

# --privilegedフラグは絶対に使わない(ホストへの完全アクセスを許可してしまう)
# docker run --privileged myimage  ← NG!

⑥ 読み取り専用ファイルシステムで実行する

コンテナのファイルシステムを読み取り専用にすることで、マルウェアがファイルを書き換えることを防げます。

# 読み取り専用で起動(書き込みが必要な場所はtmpfsで指定)
docker run --read-only --tmpfs /tmp myimage

⑦ ネットワークを適切に分離する

コンテナ間の不要な通信を防ぐため、ネットワークを用途ごとに分離しましょう。

# カスタムネットワークを作成して使用
docker network create --driver bridge myapp-network

# コンテナをカスタムネットワークに接続
docker run --network myapp-network myimage

# 外部ネットワークへのアクセスを完全に遮断
docker run --network none myimage

⑧ イメージの脆弱性スキャンを定期実行する

Dockerイメージに含まれるパッケージには既知の脆弱性が含まれている場合があります。定期的にスキャンして脆弱性を検出しましょう。

# Docker Scoutで脆弱性スキャン(Docker Desktop / CLI)
docker scout cves myimage
# Trivyを使ったスキャン(OSSツール)
# インストール
sudo apt-get install -y trivy
# スキャン実行
trivy image myimage

⑨ Dockerデーモンへのアクセスを制限する

Dockerソケット(/var/run/docker.sock)はDockerデーモンへの完全なアクセスを許可します。コンテナにマウントするのは危険なため、原則として避けてください。

# NG:ソケットをコンテナにマウントするのは危険
# docker run -v /var/run/docker.sock:/var/run/docker.sock myimage

# Dockerデーモンにリモートアクセスする場合はTLSを必ず使う
# /etc/docker/daemon.json
{
  "tls": true,
  "tlscert": "/etc/docker/server.pem",
  "tlskey": "/etc/docker/server-key.pem",
  "tlscacert": "/etc/docker/ca.pem"
}

⑩ ログとモニタリングを設定する

コンテナの動作を監視することで、不審なアクティビティを早期に検出できます。

# コンテナのログを確認
docker logs <コンテナID>
# リアルタイムで確認
docker logs -f <コンテナID>
# コンテナのリソース使用状況を確認
docker stats

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

チェック項目対応方法
非rootユーザーで実行DockerfileにUSER命令を追加
信頼できるベースイメージ公式イメージ+具体的なタグを使用
機密情報をイメージに含めない環境変数またはDocker Secretsを使用
最小限のケーパビリティ–cap-drop ALL から必要分だけ追加
読み取り専用ファイルシステム–read-onlyオプションを使用
ネットワーク分離カスタムブリッジネットワークを使用
脆弱性スキャンTrivy / Docker Scoutを定期実行
Dockerソケットのマウント禁止-v /var/run/docker.sockを使わない

まとめ

  • コンテナは必ず非rootユーザーで実行する
  • ベースイメージは公式・最小限・タグ固定が基本
  • パスワードやAPIキーは環境変数やDocker Secretsで管理する
  • 不要なケーパビリティは削除し、読み取り専用で実行する
  • 定期的な脆弱性スキャンでリスクを早期発見する

セキュリティ対策は一度やれば終わりではなく、継続的な見直しが重要です。本番環境に持っていく前に必ずこのチェックリストを確認してください。

コメント

タイトルとURLをコピーしました