Dockerコンテナのroot権限実行の危険性と対処法

Dockerコンテナのroot権限実行の危険性と対処法 Docker

Dockerコンテナを本番環境で運用する際、セキュリティは最も重要な考慮事項の一つです。
多くの開発者が見落としがちなのが、コンテナをroot権限で実行することのリスクです。
本記事では、root権限での実行がもたらす具体的な危険性と、適切な対処方法について実践的なサンプルコードとともに解説します。

root権限での実行による主な危険性

ホストシステムへの影響拡大

コンテナがroot権限で実行されている場合、コンテナが侵害されるとホストシステム全体への影響が拡大する可能性があります。

権限昇格攻撃のリスク

攻撃者がコンテナ内でroot権限を取得した場合、Docker Daemonやホストのリソースへのアクセスを試みる可能性があります。

ファイルシステムの不正操作

ボリュームマウントを通じて、ホストのファイルシステムに対する不正な読み取り・書き込みが行われるリスクがあります。

実践的セキュリティ検証

以下のサンプルコードを使用して、root権限実行時とそれ以外の場合のセキュリティリスクを実際に確認できます。

検証用Dockerfileの作成

root権限で実行される脆弱な例。

非root権限で実行される安全な例

セキュリティリスク検証用のPythonアプリケーション

vulnerable-app.py

以下のpythonスクリプト(vulnerable-app.py)は、Dockerコンテナのセキュリティリスクを評価するために設計されています。
具体的には、コンテナがroot権限で実行されているかをチェックし、さらにファイルシステムへの書き込みやシステム情報の取得といった「危険な操作」を試行することで、コンテナの現在の権限レベルと、それによって実行可能な操作の範囲を検証します。

secure-app.py

このPythonスクリプト(secure-app.py)は、Dockerコンテナのセキュリティを検証するためのツールです。
コンテナがroot権限で実行されているかを確認し、さらにシステムファイルへのアクセスやシステム情報の取得といった「危険な操作」を試行することで、コンテナの現在の権限レベルと、それによって可能になる操作の範囲を評価します。

検証の実行方法

脆弱なコンテナ(root権限)のビルドと実行を行う。

セキュアなコンテナ(非root権限)のビルドと実行を行う。

比較のため、同じイメージ(security-test-vulnerable)を異なる権限で実行する。

詳細なリスク検証

危険なコマンド例

ホストルートディレクトリの完全マウント

ホストシステムの様々な重要なディレクトリをコンテナ内にマウント後し、ubuntu:20.04イメージのコンテナのbash シェルを起動する。

Docker Socket マウントによる権限昇格テスト

このコマンドは、Dockerコンテナ内でホストのDockerデーモンを操作できるようします。
Dockerのソケットとバイナリの両方をマウントします。

これにより、コンテナ内からあたかもホスト上で直接Dockerコマンドを実行しているかのように、他のコンテナを管理したり、イメージを操作したりできるようになります。

検証スクリプト(volume-security-test.py)を使ったテスト

このPythonスクリプト(volume-security-test.py )は、Dockerコンテナがホストシステムに不適切にマウントされたボリュームを介して、どの程度のセキュリティリスクを抱えているかを検証します。

様々なテストを実行し、コンテナがホストのファイルシステムにアクセスできるか、機密ファイルを読み取れるか、さらには権限昇格が可能かなどを評価します。

volume-security-test.pyをroot権限で実行する

volume-security-test.pyを非root権限で実行する

実際の攻撃シナリオの検証

ホストのcrontabを改ざんしてバックドアを仕込む

ボリュームマウント (-v /:/host)を行いコンテナがホストのユーザーのホームディレクトリにアクセスできるようにした後に、ホストの crontab を変更して、毎分スクリプト(/tmp/backdoor.sh)を実行するようにする。

【参考】cron と crontab
cron(実際にジョブを実行するデーモン)が、crontab(ジョブのスケジュールを記述する設定ファイル)に従い指定されたコマンドを自動実行する。
crontab の基本的な書式 
分 時 日 月 曜日 コマンド
:0~59 :0~23 :1~31 :1~12 曜日:0~7(0と7は日曜) *:ワイルドカード

SSH関連ファイルの検索

ボリュームマウント (-v /home:/host-home)を行いコンテナがホストのユーザーのホームディレクトリにアクセスできるようにした後に、ホストシステム上の各ユーザーの .ssh ディレクトリを見つけ、その中身をリスト表示する。

Docker in Docker(DinD)

Dockerコンテナ内でDockerコマンドを実行する。
Dockerソケットを悪用してコンテナから脱出(Escape)し、ホストのファイルシステムを直接操作する

【コマンド解説】
第一段階
docker:latestイメージを使用してコンテナを起動し、ホストのDockerソケットをマウントすることで、ホストのDockerデーモンを制御できる様にする。

第二段階
この制御能力を利用して、ホスト上で新しいコンテナを起動します。
この新しいコンテナは、ホストのルートファイルシステム (/) を自身にマウントしています。

第三段階
ホストのファイルシステムにアクセスできるようになった内側のコンテナは、ホストの /tmp ディレクトリに pwned.txt というファイルを作成し、「Escaped to host via Docker socket」というメッセージを書き込みます。
これは、攻撃が成功し、ホストが侵害されたことを示す証拠となります。
【参考】docker.sock
docker.sockは、Docker デーモンとクライアントが通信するための UNIX ソケットファイルのこと。

Dockerは、クライアント・サーバー構造
クライアント(dockerコマンド):操作指示を送る
デーモン(dockerd):実際にコンテナを作成・削除するバックグラウンドプロセス
この両者の通信に使われるのが、docker.sock という UNIX ドメインソケットファイルです。

危険性
docker.sockにアクセスできると、クライアントは Docker デーモンとフルアクセスで通信できます。
・コンテナの作成・削除
・イメージのビルド・削除
・ネットワーク・ボリューム管理 など
が可能になります。

対処⽅法

非rootユーザーでの実行

非rootユーザーを作成した後に、ファイルの所有権を非rootユーザーに変更し、ユーザーをrootから非rootユーザーへ切り替えてからアプリを起動する。

Docker User Namespace(ユーザー名前空間)の活用

DockerにおけるUser Namespace(ユーザー名前空間)は、コンテナセキュリティを大幅に向上させるための重要な機能です。

簡単に言えば、コンテナ内のrootユーザーを、ホスト上の非特権ユーザーにマッピングすることで、仮にコンテナが侵害されたとしても、ホストシステムへの影響を最小限に抑えることを目指します。

User Namespaceとは何か?

Linuxカーネルの名前空間(Namespace)機能の一つで、プロセスが「どのユーザーID(UID)とグループID(GID)を持っているか」という認識を隔離するものです。

  • 通常のDockerコンテナ
    デフォルトでは、コンテナ内のrootユーザー(UID 0)は、ホストシステム上のrootユーザー(UID 0)として認識されます。これは、コンテナがブレイクアウト(脱出)した場合に、攻撃者がホスト上でroot権限を取得するリスクがあるため、セキュリティ上の懸念となります。
  • User Namespaceを有効にした場合
    コンテナ内のrootユーザー(UID 0)は、ホストシステム上とは異なり権限の低いUID/GIDとして認識されるようになります。

Docker User Namespace の設定手順

ステップ1: サブUID/GID範囲の設定
Dockerデーモンで userns-remap: "default" を設定すると、Dockerは自動的に dockremap ユーザーとグループを作成し、/etc/subuid および /etc/subgid に対応するサブUID/GID範囲を割り当てます。

例
myuser という既存のユーザーにサブUID/GIDを割り当てるには、以下のファイルを編集します。
/etc/subuid
/etc/subgid

各ファイルに以下の形式で追記します。
<username>:<starting_uid>:<uid_count>
例えば、myuser にUID 100000から65536個のUIDを割り当てる場合
/etc/subuid に下記を追記
myuser:100000:65536

/etc/subgid に下記を追記
myuser:100000:65536

ステップ2: Dockerデーモンの設定ファイルを編集
Dockerデーモンの設定ファイルは通常 /etc/docker/daemon.json にあります。
このファイルを作成または編集して、User Namespace Remappingを有効にします。

/etc/docker/daemon.jsonファイルの編集

default を使用する場合:
{
  "userns-remap": "default"
}
default を使用する場合は、Dockerが自動的に dockremap ユーザー/グループを作成し、UID/GID範囲を割り当てます。

特定の既存ユーザーを使用する場合:
{
  "userns-remap": "myuser"
}

ステップ3: Dockerデーモンの再起動
設定変更を適用するために、Dockerデーモンを再起動します。

Dockerコンテナの最小権限の原則の適用

コンテナやその中で動作するプロセスに、実行に必要最小限の権限のみを与えるというセキュリティの原則を適用する方法です。

【説明】
user: "1001:1001":
コンテナ内のプロセスを root ユーザー(UID 0)ではなく、UID 1001、GID 1001 の非特権ユーザーとして実行するように強制します。

read_only: true:
コンテナのルートファイルシステムを読み取り専用に設定します。

cap_drop:
 - ALL 
コンテナから不要なLinuxケーパビリティ(能力)を全て削除します。

cap_add:
アプリケーションの動作に最低限必要なケーパビリティだけをに追加します。
- NET_BIND_SERVICE
1024番未満のポートにバインドする権限を与えます。
通常、非特権ユーザーは1024番未満のポートにバインドできませんが、ウェブサーバーなどがポート80や443をリッスンする場合に必要になります。

security_opt:
コンテナのセキュリティに関連する追加オプションを設定します。
- no-new-privileges:true
コンテナ内のプロセスが追加の特権を取得することを防ぎます。

セキュリティスキャンの実装

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

Dockerイメージは、アプリケーションとその依存関係をパッケージ化したものであり、その中に既知の脆弱性が含まれている可能性があります。これらを特定するために以下のツールが使用されます。

docker scout quickview myapp:latest

docker scout:Docker社が提供するイメージセキュリティツール。
quickview:Docker Scout の簡易レポート機能で、指定したイメージ(ここでは myapp:latest)に含まれる脆弱性や依存関係の問題の概要を表示する。

docker scan myapp:latest

docker scan:Snyk(スニーク)という脆弱性スキャンツールと統合されており、Dockerイメージ内のオープンソースライブラリや依存関係に潜む脆弱性を詳細に分析。

このコマンドは現在非推奨(deprecated)になる傾向があり、将来的には docker scout に統合される見込み

設定のセキュリティチェック

docker bench-security

docker bench-security は、Dockerコンテナのセキュリティに関するベストプラクティスを評価するためのスクリプトです。
これは、CIS (Center for Internet Security) の「CIS Docker Benchmark」に基づいています。
このベンチマークは、Dockerのセキュリティ設定に関する具体的な推奨事項をまとめたものです。

GitHubのdocker/docker-bench-security から取得して実行します。

実行時のセキュリティ制限

Dockerコンテナを起動する際に、様々なセキュリティオプションを付与して実行する。

--user 1001:1001
コンテナ内で実行されるプロセスのユーザーとグループを指定。

--read-only
コンテナのルートファイルシステムを読み取り専用する。

--tmpfs /tmp:rw,noexec,nosuid,size=100m
一時ファイルシステム(tmpfs)をコンテナ内にマウントし、そのプロパティを細かく制御する。

--cap-drop=ALL
コンテナからすべてのLinuxケーパビリティ(capabilities)を削除する。

--cap-add=NET_BIND_SERVICE
--cap-drop=ALL で削除したケーパビリティのうち、アプリケーションの実行に必要不可欠なものだけを明示的に追加する。

--security-opt=no-new-privileges:true
コンテナ内のプロセスが、setuidやsetgidビットを持つ実行ファイルを介して新たな特権を取得するのを防ぐ。

まとめ

Dockerコンテナをroot権限で実行することは、セキュリティ上の重大なリスクをもたらします。

本記事で紹介した検証コードを実際に実行することで、その危険性を体感できます。

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