Docker Bench for Security:CIS基準でDockerホストの脆弱性を5分でスキャン

Docker tutorial - IT technology blog
Docker tutorial - IT technology blog

現実的な問題:Dockerは思ったほどデフォルトで安全ではない

半年前、私はある金融プロジェクトで20個のマイクロサービスが稼働するDockerクラスターを管理していました。CI/CDによってイメージが継続的にデプロイされ、コンテナは自動でスケールし、ログはGrafanaに順調に送られていました。私は、Dockerがアプリケーションを十分に隔離できていると信じ切っていました。たとえハッカーが侵入したとしても、そのコンテナという「箱」の中に閉じ込められるだけだろうと考えていたのです。

しかし、セキュリティチームから送られてきた15ページに及ぶ監査レポートによって、その考えは一変しました。そこには40以上の深刻なセキュリティ欠陥が指摘されていました。Dockerデーモンがroot権限で実行されていること、ソケットが露出していること、そしてコンテナにリソース制限が全く設定されていないこと。さらに悪いことに、多くのイメージが3年前の古いNode.jsバージョンを使用しており、Criticalな脆弱性が満載でした。この時、非常に高価な教訓を得ました。「Dockerを動かせること」と「安全に運用できること」は全く別物であるということです。

もしあなたが docker run を実行するだけで、ホストやデーモンの設定を無視しているなら、システムは簡単に権限昇格(privilege escalation)攻撃の標的になります。サーバーが仮想通貨のマイニングマシンに変えられてしまう前に、セキュリティ対策を始めましょう。

なぜDockerのデフォルト設定は危険なのか?

Dockerはユーザーが「すぐに動かせる」という利便性を優先しています。しかし、この利便性には潜在的なリスクが伴います。

  • 過剰な権限: Dockerデーモンはデフォルトでroot権限で動作します。もし誤って /var/run/docker.sock を乗っ取られたコンテナにマウントしてしまうと、ハッカーはホストマシン全体を制御できてしまいます。
  • 膨大なCIS基準: CIS Docker Benchmark という基準には100以上のチェック項目があります。新しいサーバーをデプロイするたびに、数百ページのPDFを手動で照らし合わせる忍耐力のある人はいないでしょう。
  • ランタイムの脆弱性: 私たちは通常、コンテナが「Up」しているかどうかだけを確認しがちです。しかし、--privileged のような危険なフラグを立てて実行されていないかまで注意を払う人はほとんどいません。

一般的なセキュリティチェックの手法

最適なツールに出会う前、私はいくつかの従来の手法を試しました:

  1. 手動でのハードニング: 設定ファイルを自分でチェックし、/etc/docker の権限を再設定し、auditd を構成します。この方法は非常に時間がかかり、ミスも起こりやすいです。セキュリティ資格の勉強中であれば適しているかもしれません。
  2. 自作のBashスクリプト: 数値を素早くチェックするためのスクリプトを書く人もいます。しかし、これらのスクリプトはDockerのバージョンが更新されるとすぐに古くなってしまいます。
  3. 高価なSaaSツール: Prisma CloudやSnykのようなソリューションは非常に強力です。しかし、スタートアップや個人のプロジェクトにとって、毎月数千ドルのコストは大きな障壁となります。

Docker Bench for Security:コスパ最強のツール

多くの試行錯誤の結果、私は Docker Bench for Security が最適なソリューションであると結論付けました。これはコンテナとしてパッケージ化されたオープンソースのスクリプトです。CISベンチマークの全基準に基づいて、システムを自動的にスキャンします。

私が管理している本番環境では、このツールを毎週実行するようにスケジュールしています。これにより、RAM制限の忘れといった初歩的なミスを即座に発見できます。こうしたミスは、一つのコンテナの不具合がサーバー全体をダウンさせる原因になります。

1. 10秒でできるクイックデプロイ

最大のメリットは、ホストマシンに追加のインストールが一切不要なことです。以下のコマンドを実行してイメージをプルし、スキャンを開始するだけです:

docker run --rm -it --network host --pid host --userns host --cap-add audit_control \
    -e DOCKER_CONTENT_TRUST=$DOCKER_CONTENT_TRUST \
    -v /etc:/etc: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 \
    --label docker_bench_security \
    docker/docker-bench-security

重要なパラメータの解説:

  • --pid host: デーモンの整合性をチェックするために、ホスト上で実行中のプロセスをツールが監視できるようにします。
  • -v /var/run/docker.sock:/var/run/docker.sock: ツールがDocker APIと直接通信できるようにします。
  • --rm: スキャン終了後にコンテナを自動的に削除し、サーバーをクリーンに保ちます。

2. スキャン結果の分析

結果は色分けされて表示されるため、非常に分かりやすいです:

  • [PASS]: 基準に従って安全に設定されています。
  • [WARN]: 検討が必要なセキュリティリスクの警告です。
  • [INFO]: 参考情報です。
  • [NOTE]: 即座に対処が必要な深刻な問題です。

レポートは主に、ホスト構成、デーモン設定、システムファイルの権限、イメージのセキュリティ、およびコンテナのランタイム状態の5つのグループに焦点を当てています。

3. 修正の実践:内部攻撃を阻止する

最初の実行後、私のサーバーでは [WARN] 2.1 - Ensure network traffic is circumscribed... というエラーが出ました。これは、デフォルトのbridgeネットワーク内のコンテナ同士が自由に通信できてしまうことを意味します。もし一つのコンテナがマルウェアに感染すると、他のコンテナを容易に攻撃できてしまいます。

私は /etc/docker/daemon.json ファイルを以下のように設定することで、この問題を完全に解決しました:

{
  "icc": false,
  "userns-remap": "default",
  "no-new-privileges": true
}

その後、サービスを再起動するだけです:

sudo systemctl restart docker

わずか3行の設定で、コンテナ間通信(ICC)を遮断し、システムの隔離性を高めることができました。

4. 監視プロセスの自動化

セキュリティ対策を一過性のものにしないでください。私はCronjobを設定してDocker Benchを毎週実行し、結果をSlackに直接送信するようにしています。誰かがデプロイ時に誤って –privileged フラグを有効にした場合、5分以内に通知を受け取ることができます。

# ログを毎週自動保存するスクリプト
docker run --rm --network host --pid host docker/docker-bench-security > /var/log/docker-bench-$(date +%F).log

導入から6ヶ月後の成果

Docker Benchを運用フローに取り入れたことで、明らかな変化がありました:

  • イメージ作成スキルの向上: 開発チームはroot権限を使う習慣をやめ、代わりにDockerfileで USER 命令を使用するようになりました。
  • リソースの安定化: CPU/RAM制限を強制したことで、メモリリークによるサーバーの予期せぬフリーズがなくなりました。
  • 顧客からの信頼: 定期的な監査の際、Docker Benchのログを提出するだけで、システムが国際基準に準拠していることを証明できるようになりました。

デフォルト設定を過信しないでください。今日、5分だけ時間を割いてDocker Bench for Securityを試してみてください。結果を見て少し「冷や汗をかく」かもしれませんが、後で事故対応をするよりも、今修正する方がはるかに賢明です。もし [WARN] エラーの修正で困ったことがあれば、ぜひ下にコメントを残してください!

Share: