Rootlessコンテナを使うべき理由
Be Using Rootless Containers (blog.miguelgrinberg.com)
要約
この記事は、Dockerの従来のインストール方法におけるセキュリティリスクについて解説しています。デーモンがroot権限で実行されるため、root権限昇格の脆弱性が生じる可能性があります。利便性のためにユーザーをdockerグループに追加する一般的な設定がこのリスクを増大させます。著者は、より安全な代替手段として、rootlessモードのDockerやPodmanといったrootlessコンテナを紹介し、その利点と、レジストリ設定やデーモンレス運用などの注意点について説明しています。
全文翻訳
ルートレスコンテナを使うべき理由
先日、新しいLinuxディストリビューションの一つ(人種差別主義者が率いるもので、ここでは言及しません)で深刻な脆弱性が公表されました。この問題は、インストーラーがデフォルトで適用した非標準のDocker設定が原因で、この設定がセキュリティリスクを生み出していることをユーザーに警告することなく、セキュリティリスクを生み出していたという点で興味深いものでした。最終的な結果として、これらのシステム上で実行されているあらゆるプロセスが、パスワードやsudo、あるいはユーザーへのプロンプトなしにroot権限に昇格できる可能性がありました。
このインシデントは私自身には影響しませんでしたが、Dockerを安全に設定することの難しさを改めて認識させられました。Dockerの抱える問題点と、それに対処するために何ができるかについて理解したいのであれば、あなたは正しい場所にいます。
Dockerの問題点
Dockerのセキュリティ問題は、初期の段階でクライアント・サーバーアーキテクチャを採用するという選択に端を発しています。標準的なインストールでは、Dockerデーモンはrootユーザーとしてバックグラウンドで動作し、APIを通じてすべての機能を提供します。docker-cliのようなクライアントは、サーバーがリッスンしているDockerソケットを通じてこのAPIにリクエストを送信します。
Dockerデーモンはrootユーザーとして実行されるため、それにアクセスを奪った攻撃者はroot権限でコードを実行できます。これは理論的なもの、あるいは天才ハッカーだけが利用できる、ありそうもない、非常に複雑で難解な脆弱性だと考えるかもしれません。しかし、考え直してください。
以下に、パスワードを使用せずに、私のUbuntu 26.04システムでrootアクセスを取得する方法を示す簡単な例を示します。
# 通常のユーザーとしては、以下のコマンドは失敗します
$ ls /etc/sudoers.d/
ls: ディレクトリ '/etc/sudoers.d/' を開けません: 権限がありません
# しかし、Dockerにこのコマンドを実行するように依頼でき、質問なしで成功します!
$ docker run -v /:/host alpine:latest ls /host/etc/sudoers.d/
90-cloud-init-users
README
これがどのように機能するかが不明な場合、上記のdocker runコマンドは標準のAlpine Linuxコンテナを起動し、ホストのファイルシステム全体を/hostパスの下にマウントします。コンテナはDockerデーモンを通じてrootアカウントで実行されているため、すべてのファイルにアクセスでき、docker runコマンドを発行したユーザーのあらゆる制限をバイパスできます。認証やパスワードの入力は一切不要で、コマンドはそのまま機能しました。少し巧妙な悪意のあるスクリプトは、同じ技術を使用してシステムファイルを変更または窃取したり、cronジョブなどをインストールしたりする可能性があります。すべてユーザーが気づかないうちにです。
さて、嘘はつけません。上記のroot権限昇格攻撃は、すべてのDockerインストールで機能するわけではありません。Dockerの基本的なインストールを行う場合、「root権限昇格」にはあまり意味がありません。なぜなら、デフォルトのインストールではdockerコマンドはrootユーザーのみがアクセスできるからです。通常のユーザーアカウントからDockerを使用したい場合は、sudo dockerを実行する必要があり、それには認証が必要です。
このような攻撃が可能になるのは、ユーザーが利便性を求めてDockerソケットへのアクセス権限を緩和することが多いためです。人々が行う非常に一般的な非標準の設定変更は、自分のマシン上のdockerグループに追加することです。これにより、sudoなしでdockerコマンドを実行できるようになります。これは、私が上記のデモンストレーションで行ったこと、そして冒頭で言及したLinuxディストリビューションがユーザーに通知せずに実行したことでもあります。
真実は、Dockerをrootユーザーとしてのみ使用することは信じられないほど不便であるということです。それほどまでに、sudoなしで動作するように再設定する方法についての詳細は、セキュリティ上の悪夢であるにもかかわらず、公式Dockerウェブサイトに文書化されています。LinuxでDockerを使用している場合、この変更を行った可能性が高く、したがって、あなたのシステムはroot権限昇格攻撃に対して脆弱であると推測します。
macOSとWindowsでのDockerはどうですか?
上記で議論したことはすべてLinuxでのDockerの実行に関連しています。実際、DockerはLinuxでしか実行されないため、他のオペレーティングシステムをサポートするDocker Desktopのような製品は、Dockerを実行できるようにするためにLinux仮想マシン(VM)を作成するというトリックを使用する必要があります。
私は正直、これらのソリューションがどのように機能するかについてはあまり詳しくありませんが、QEMU、Hyper-Vなどの標準的な仮想化ツールが、DockerをホストするLinux VMをホストするために使用されていると想像します。これにより、物理ホストからの分離の追加レイヤーが作成されるため、これらのオペレーティングシステムでDockerを実行する場合、ホストへのリスクは大幅に軽減されるという印象を持っています。これらのツールでの経験がある方が、詳細をコメントセクションで共有したい場合は、お気軽にどうぞ。
Windowsに付属するネイティブLinuxサポートであるWSLは、特別なケースとして扱う必要があると思います。WSLはOSとの統合がはるかにタイトで、Linuxカーネルがホストで直接実行されます。そのため、通常のLinuxシステムに存在するリスクと同様のリスクが存在する可能性があります。この件について共有したいことがある場合は、ぜひ聞かせてください。
代替手段:ルートレスコンテナ
前述のように、Dockerはクライアント・サーバーアーキテクチャを採用するという決定を下しました。これが、主に従来のroot所有のデーモンにつながりました。しかし、rootユーザーに依存しないコンテナを実行するための代替方法があります。多くの代替プラットフォームの中で、2つ言及したいと思います。
- ルートレスモードのDocker: 標準Dockerのインストールプロセスのバリエーションで、デーモンはユーザーレベルのサービスとして実行されます。
- Podman: デーモンレスのコンテナプラットフォーム。
ルートレスDockerソリューションは少しハック的だと感じます。公式のインストール手順では、通常のインストールを行い、Dockerデーモンを無効にしてから、提供されたスクリプトを実行して現在のユーザーのユーザーレベルデーモン置換を作成するように求められます。
Podmanの場合、インストールするだけで完了します。さらに、システムでバックグラウンドサービスを実行する必要がないという利点があります。podmanをdockerの代わりにタイプすることに慣れる(またはシェル設定にalias docker=podmanを追加する)と、ワークフローの大部分は同じように機能する可能性が高いですが、すべてのコンテナはあなたのユーザーの下で実行され、root権限昇格の実行可能なパスはありません。そして、デーモンを実行しません(必要ない限り、以下を参照)。
Podmanの注意点
Podmanのどこが気に入らないのでしょう?完璧に見えます。初期からDockerを悩ませてきたセキュリティ問題を解決しています。
さて、上で「ワークフローの大部分」がPodmanとDockerで同じように機能すると慎重に述べたことに注意してください。実際には、すべてのワークフローを透過的に切り替えることができるわけではありません。移行中に経験した問題点をいくつかレビューしましょう。
Dockerはデフォルトでイメージをプルする際に独自のDocker Hubレジストリを使用しますが、Podmanは設定方法によってはそうしない場合があります。次のコマンドを見てください。
docker pull postgres
これはPodmanでは失敗する可能性があります。なぜなら、イメージをどこからプルするかを知らないかもしれないからです。Docker Hub(または使用する他のレジストリ)をデフォルトレジストリとして設定することは可能ですが、Podmanを使用する場合は、すべてのコンテナイメージに完全修飾アドレスを付けて名前を付けることに慣れるのが最善だと感じています。
podman pull docker.io/library/postgres
デーモンレスであるため、Podmanにはいくつかの顕著な違いもあります。
デーモンがないため、Podmanは再起動後にコンテナを再起動できません。そのため、24時間年中無休で稼働する必要があるサーバーでPodmanを使用するには、追加の作業が必要です。Podmanは、コンテナを個別のサービスとしてインストールできるpodman quadletコマンドグループの下でsystemdとの統合を含んでいます。
同様に、デーモンがない場合、アプリケーションはAPIを介してコンテナをどのように起動または対話するのでしょうか?これは、Dockerを使用する非常に一般的な方法です。
このために、PodmanはオプションのAPIサービスを提供しており、これはpodman system serviceコマンドで起動できます。このコマンドは、使用したいソケットアドレスと、サービスがアクティブであるオプションの時間を受け入れます。起動すると、サービスはそれを起動したユーザーのためにのみ実行され、Dockerのものと互換性のあるAPIを公開します。サーバーの場合、このユーザーレベルサービスをバックグラウンドで常に実行しておくためのsystemd統合もあります。
結論
ルートレスコンテナがシステムをより安全にする方法について、より明確な見解が得られたことを願っています。あるいは、ルートレスコンテナがあなたには合わないと判断するのに役立ったかもしれません。Dockerのroot権限昇格のリスクは、あなたが許容できるものであると。それは私が推奨することではありませんが、それらのリスクが何であるかを理解しているのであれば、大丈夫だと思います。
私自身は、最近では主にPodmanを使用しています。また、Docker ComposeのクローンであるPodman Composeもかなり利用しています。時折Podman APIを起動しますが、ほとんどの場合必要ないので、APIサービスを実行せずにすべてpodmanコマンド経由で行っています。Dockerも時々使用しますが、セキュリティがそれほど懸念されない、使い捨ての分離されたVMでいくつかの簡単なテストを行う場合にのみ使用します。
私のブログを訪れてくれてありがとう!この記事を楽しんでいただけたなら、Buy me a coffeeを通じて少額のワンタイム寄付で私の仕事をサポートし、私を元気づけてくれることを検討してください。ありがとう!