コンプライアンス
Dockerコンテナを特権モードで実行することが危険な理由
Docker の「Privileged(特権)」コンテナ(以下、特権コンテナ)は、簡潔に言えば、ホストコンピュータに対するすべてのルート権限を備えたコンテナであり、通常のコンテナではアクセスできないリソースへのアクセスが可能となります。特権コンテナの使用例の1つにDockerコンテナ内でDockerデーモンを実行することがあります。
Docker の「Privileged(特権)」コンテナ(以下、特権コンテナ)は、簡潔に言えば、ホストコンピュータに対するすべてのルート権限を備えたコンテナであり、通常のコンテナではアクセスできないリソースへのアクセスが可能となります。特権コンテナの使用例の1つにDockerコンテナ内でDockerデーモンを実行することがあります。もう1つの使用例は、コンテナがハードウェアに直接アクセスする必要がある場合です。前者の例である、コンテナ内でコンテナを操作する「Docker-in-Docker」は、Docker自体の開発の目的で導入されました。今日では、オープンソースの自動化サーバJenkinsでの継続的インテグレーションおよび継続的デリバリー(CI / CD)タスクの自動化など、特権コンテナの実行にはさまざまなユースケースが存在します。ただし、特権コンテナの実行は必ずしも安全ではありません。このブログ記事では、セキュリティ保護が十分でない特権コンテナが、どのように企業や組織のシステムへサイバー犯罪者による侵入を許すことになるかを解説します。
■特権コンテナの問題点
一般に、「Docker-in-Docker」は、コンテナの実行中にもう一つ別のコンテナを生成する必要がある場合に使用されます。ただし、保護をせずに特権コンテナを使用した場合、いくつかの深刻な影響が懸念されます。
特権コンテナを実行すると、組織内部のユーザはホストのリソースへの高度なアクセス権限を持つことになります。しかしこれは、攻撃者に悪用された場合も同等のアクセスが可能になることを意味します。特権コンテナを利用する攻撃に必ずしもリモートコードの実行は伴いませんが、実行された場合、攻撃可能な対象は広範囲に及びます。特権コンテナを利用する目的はアクセス権限を強化するためであり、攻撃者がルート権限でコードを実行できる可能性が高くなります。これは、攻撃者が、全能ともいえる「CAP_SYS_ADMIN」をはじめ、利用可能なすべてのケーパビリティでの完全なルートアクセスを実行できることを意味します。また、cgroups、AppArmor、SECcompなど、セキュリティを追加する他の隔離機能が放棄される、あるいは無効化されることにも注意が必要です。
露出している特権コンテナにアクセスを試みる攻撃者にとって、その利用目的は無限に存在すると言えます。攻撃者は、ホストコンピュータで実行されているソフトウェアを識別し、ソフトウェアの持つ脆弱性を利用することができます。また、コンテナソフトウェアの脆弱性や、脆弱なパスワードを利用するコンテナまたは認証チェックの全くないコンテナなどの不用意な設定を狙うという可能性もあります。攻撃者の手にルートアクセス権限があるため、不正なコードや、コインマイナーなどのマルウェアが実行され、しかもうまく隠蔽されてしまう可能性があります。
■コンテナを隔離する
アプリケーションの基本コンポーネントが含まれるコンテナは、本来は隔離された環境です。単一のホストコンピュータ内で複数のプロセスを独立して実行することができるように、コンテナエンジンはさまざまなカーネル機能を使用します。DockerコンテナはLinux環境上で実行されるためLinuxカーネルのリソースを区切る機能を利用して独立して実行されます。これらの1つはLinuxのNamespace(名前空間)と呼ばれます。表1は、この名前空間の種類を示しています。
名前空間 | 概要 |
MNT (Mount) | ファイルシステムのマウントポイントを管理する |
PID (Process) | プロセスを隔離する |
NET (Network) | ネットワークインターフェイスを管理する |
IPC (Inter-process communication) | IPCリソースへのアクセスを管理する |
UTS (Host name) | カーネルとバージョン識別子を隔離する |
CGROUPS | 複数のプロセスのリソース使用量を制限、隔離、測定する |
User ID (User) | 特権の隔離とユーザ識別の分離を提供する |
デフォルトでは、Dockerデーモンおよびコンテナのプロセスは、ルート権限で実行されます。ただし、別のユーザを作成してアクセス権限を下げることも可能となっており、セキュリティの観点からはそのようにすることが強く推奨されます。
特権コンテナ内でルートアクセス権限を持つことは、ホストコンピュータにおいてもルートアクセス権限を持つことを意味します。しかし表2に示すように、コンテナプロセスのデフォルトのケーパビリティセットは限られていることに注意してください。ただし、特権コンテナはすべてのケーパビリティを持つことになります。
ケーパビリティ | 許可される操作 |
CAP_AUDIT_WRITE | レコードをカーネル監査のログに書き込む |
CAP_CHOWN (Change owner) | ファイルのUIDとGIDを任意に変更する。ファイル、ディレクトリ、リンクの所有者とグループを変更する |
CAP_DAC_OVERRIDE (Discretionary access control) | ファイルの読み出し、書き込み、実行の権限チェックをバイパスする |
CAP_FOWNER | CAP_DAC_OVERRIDEおよびCAP_DAC_READ_SEARCHによりチェックが行われる操作を除き、通常、プロセスのファイルシステムUIDがファイルのUIDと一致することが要求される操作の権限チェックをバイパスする |
CAP_FSETID | ファイルが変更されたときにset-user-IDおよびset-group-IDの許可ビットをクリアしない |
CAP_KILL | シグナルを送信する際の権限チェックをバイパスする |
CAP_MKNOD | 特殊ファイルを作成する |
CAP_NET_BIND_SERVICE | インターネットドメインの特権ポート(1024未満のポート番号)にソケットをバインドできる |
CAP_NET_RAW | RAWソケットおよびPACKETソケットを使用し、透過プロキシ用の任意のアドレスにバインドする |
CAP_SETGID | プロセスGIDおよび補足GIDリストに対する任意の操作を行う |
CAP_SETPCAP | ファイルケーパビリティがサポートされている場合(Linux 2.6.24以降):呼び出し元のスレッドのバウンディングセットの任意のケーパビリティを継承可能なケーパビリティセットに追加する。バウンディングセットからケーパビリティを削除する。securebitsフラグを変更する ファイルケーパビリティがサポートされていない場合(Linux 2.6.24より前のカーネル):呼び出し元が許可されているケーパビリティセットに含まれる任意のケーパビリティを他のプロセスに付与したり、削除したりする |
CAP_SETUID | プロセスUIDに対する任意の操作を行い、UNIXドメインソケット経由でソケット資格情報を渡すときにUIDを偽造し、ユーザ名前空間にユーザIDマッピングを書き込む |
CAP_SYS_CHROOT | chrootを使用し、setnsを使用して名前空間を変更する |
セキュリティ強化のため、Dockerには、Dockerfile(必要なDockerイメージを作成するためのファイル)内のUSERディレクティブを使用して、非ルートユーザ権限でコンテナプロセスを実行できるオプションがあります。ホストコンピュータのルートユーザと、コンテナのルートユーザを分離することのできるユーザ名前空間が、デフォルトでは使用されないことに注意してください。ユーザ名前空間はDockerデーモンで設定することが可能で、ルートアクセスが必要な多くの状況で使用できます。 図1に示される角括弧内の数字に注目してください。
このように、Dockerは、-userns-remapフラグで明示的に指定しなければ、ユーザ名前空間を使用することはありません。
ユーザ名前空間内では、完全な操作権限をプロセスに付与できますが、ユーザ名前空間外ではそのようにできません。これは、プロセスが、ユーザ名前空間外では非特権ユーザIDを持つことができ、ユーザ名前空間内ではルートユーザを示す ”0 ” を持つことができることを意味します。
これは、たとえプロセスがケーパビリティ「CAP_SYS_ADMIN」を使用できる新しいユーザ名前空間内で実行されており、実行されるアクションが例えばカーネルモジュールのインストールなどの特権昇格を必要とする場合でも、親ユーザ名前空間(ルートユーザ下では実行されず、必要なケーパビリティを持たない)においても要求される特権についてチェックされます。見つからない場合、アクション全体が拒否されます。
–userns-remapによってセキュリティが強化されますが、これは本記事執筆時点でまだ実験的な機能である「Rootless Docker」とは異なります。親コンテナのプロセスであるDockerデーモンは、引き続きルート権限下で実行されます。
■特権コンテナを悪用する攻撃
特権コンテナのケーパビリティがあれば、攻撃者はそれを利用してユーザのホスト環境へのルートアクセスを取得することが可能になります。
最近、トレンドマイクロの設置したハニーポットの1つで、特権コンテナを利用してホストコンピュータの/root/authorized_keys内に独自のSSH公開キーを配置しようとする攻撃者の不正活動を確認しました。
解析すると、攻撃者が特権コンテナで「/mnt」バインドを使用して、ホストのルート「/」にバインドしようとしたことが確認されました。そしてその後、以下のコマンドが実行されたことを確認しました。
- “Cmd”:[“sh”,”-c”,”mkdir -pv /mnt/root/; mkdir -pv /mnt/root/.ssh/; ls -ld /mnt/root/.ssh/; chattr -i -a /mnt/root/.ssh/ /mnt/root/.ssh/authorized_keys”]
- イミュータブル(書き換え禁止)属性を削除し、「/mnt/root/.ssh」および「/mnt/root/.ssh/authorized_keys」にある属性を追加する
図3のコードには ”Privileged:false” が示されていますが、新しいプロセスは特権コンテナのコンテキスト内で実行されるため、そのケーパビリティはその前に生成された特権コンテナのケーパビリティと一致することになります。解析によれば、 “/”,”/mnt/root ” バインドはDocker CLI内の -v /:/mnt/root と同等であるため、ホストコンピュータのファイルシステムにアクセスが可能です。
攻撃者はauthorized_keysファイルの上書きも試みたことが、図4のAPIリクエストから確認できます。
これらの例から、コンテナは本来隔離されたものであるにもかかわらず、攻撃者がそのような制限を外しホストコンピュータのリソースへのアクセス権限を獲得することにより、ユーザのインフラストラクチャが危険にさらされる可能性があることがわかります。
Dockerのprivilegedフラグは、隔離する機能を事実上無効にします。コンテナには、異なるPID名前空間およびMNT名前空間、またcgroupsプロファイルが適用される場合があります。しかし、Dockerコンテナで–privilegedフラグが実行されている場合、ユーザと、そして不本意ながら攻撃者も、ホストに接続されているハードドライブへのアクセスが可能になります。
-privilegedフラグによってルートアクセス権限を得ることになり、攻撃者が「拘束された環境からの脱出」するための多くの方法があります。
- /dev/sda1または同等の をマウントし、ホストの記憶装置へのアクセスを許可する
- ls –la /dev/
- mkdir /hdd & mount /dev/sda1 /hdd
- cgroups notify_on_releaseおよびrelease_agentを使用して、ホストのルート内でシェルを生成する
- カスタムカーネルモジュールをデプロイし、ホストでの持続的な活動を可能にする(リバースシェルなど)
■特権コンテナのセキュリティに関する推奨事項
ルート権限なしでユーザがDockerデーモンを実行できるようにすることを目的とした、実験的なRootless (非ルート)Dockerモードが、DockerのエンジニアであるTõnis Tiigi氏によって提案されています。Rootless Dockerモードを使用した場合たとえ攻撃者がDockerデーモンとコンテナに侵入したとしても、ホストコンピュータへのルートアクセス権限はありません。
開発初期段階にあるため、RootlessモードはDockerの全機能を完全にはサポートしていません。2020年12月20日現在、以下についてサポート対象外となっています。
- cgroups(cgroupに依存するdocker topを含む )
- AppArmor
- Checkpoint
- Overlay network
- Exposing SCTP ports
とはいえRootlessモードは、これらの機能を使用する確率の低いJenkinsでのビルドなどの多くのユースケースでは十分に利用可能です。
Dockerコンテナは、企業や組織が増え続ける要求に答えるために役立ちます。Dockerコンテナの利用を採用する企業が増加するに伴い、ますます多くのサイバー犯罪者が、そのようなツールのセキュリティギャップを利用しようと余念がありません。
特権モードのコンテナにはもちろん正規の使用方法がありますが、開発者は使用の際には注意を払い、規制をかける必要があります。つまるところ、特権モードのコンテナが攻撃者によって侵入ポイントとして利用された場合、不正なコードやマルウェアを侵害されたホストコンピュータへの拡散に利用される可能性に注意が必要です。
特権コンテナの使用は絶対に避けるべき、ということではありません。組織環境でそのような特権コンテナを実行するときには十分なセキュリティ保護をしてください。
特権コンテナを使用する際のセキュリティ上の推奨事項を以下に示します。
- 最小特権の原則を適用する。コンテナの実行を助けるデーモンサービスなどクリティカルなコンポーネントへのアクセスを制限する。ネットワーク接続も暗号化する
- コンテナは、内部ネットワークを含め、信頼できるソースにのみアクセスを許可するように設定する。これには、コンテナ自体の適切な認証手順の実装が含まれる
- 推奨されるベストプラクティスに従う。Dockerはベストプラクティスの包括的なリストを提供し、インストール後のDockerとの連携を強化するためにLinuxホストを構成するなど、専門家が利用できる組み込みのセキュリティ機能を備えている
- 導入を慎重に検討する。どうしてもDockerで実行する必要があるか。ルートアクセスでの実行を必要とせず効果的にジョブを実行できる他のコンテナエンジンはないか。あるいは別の方法で実行可能か。実行した場合関連するリスクは想定範囲内か
- 不審なコンテナおよびイメージをチェックするために、定期的にセキュリティ監査を実行する
■トレンドマイクロの対策
トレンドマイクロは、アプリケーションを安全にビルドし、さまざまな環境に迅速にデプロイして実行するDevOpsチームを支援します。「Hybrid Cloud Security」は、DevOps 体制を支えるセキュリティチームに対して、「XGen」アプローチにより、物理・仮想・クラウドの混在環境における最適なセキュリティを提供します。総合サーバセキュリティ製品「Trend Micro Deep Security™ 」およびコンテナイメージを保護する「Deep Security Smart Check」により、デプロイおよび実行時にコンテナイメージをスキャンすることが可能です。
参考記事:
- 「Why Running a Privileged Container in Docker Is a Bad Idea」
by David Fiser and Alfredo Oliveira
翻訳: 室賀 美和(Core Technology Marketing, Trend Micro™ Research)