インフラ・DevOps
Rootlessコンテナを使うべき理由
Be Using Rootless Containers (blog.miguelgrinberg.com)
要約
この記事は、Dockerの従来のインストール方法におけるセキュリティリスクについて解説しています。デーモンがroot権限で実行されるため、root権限昇格の脆弱性が生じる可能性があります。利便性のためにユーザーをdockerグループに追加する一般的な設定がこのリスクを増大させます。著者は、より安全な代替手段として、rootlessモードのDockerやPodmanといったrootlessコンテナを紹介し、その利点と、レジストリ設定やデーモンレス運用などの注意点について説明しています。
全文翻訳
最近、新しいLinuxディストリビューションの1つ(ここでは言及しない人種差別主義者が率いるもの)で深刻な脆弱性が公開されました。この問題は、インストーラーがデフォルトで適用した非標準のDocker設定が原因であり、この設定がセキュリティリスクを生み出していることをユーザーに警告せずに作成していたため、興味深いものでした。最終的な結果として、これらのシステムで実行されている任意のプロセスが、パスワード、sudo、またはユーザーへのプロンプトなしでroot権限に昇格できる可能性がありました。
このインシデントは私自身には影響しませんでしたが、Dockerを安全に設定することの難しさを思い出させてくれました。Dockerの課題とそれに対処する方法について理解することに興味があるなら、あなたは正しい場所にいます。
Dockerの問題
Dockerのセキュリティ問題は、初期に決定されたクライアント-サーバーアーキテクチャの選択に起因します。標準的なインストールでは、Dockerデーモンはrootユーザーの下でバックグラウンドで実行され、APIを通じてすべての機能を提供します。docker-cliのようなクライアントは、サーバーがリッスンしているDockerソケットを通じてこのAPIにリクエストを送信します。
Dockerデーモンはrootユーザーとして実行されるため、それにアクセスできる攻撃者はroot権限でコードを実行できます。これは理論的なもの、あるいは天才ハッカーだけが利用できる、ありそうもない、非常に複雑で難解な脆弱性だと考えるかもしれません。しかし、もう一度考えてみてください。ここでは、パスワードを使用せずに、Ubuntu 20.04システムでどのようにrootアクセスを取得できるかを、dockerコマンドのみを使用して示す簡単な例を示します。
# 通常のユーザーとして、次のコマンドは失敗します
$ 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アカウントで実行されているため、すべてのファイルにアクセスでき、発行したユーザーの制限をバイパスできます。認証やパスワードの入力は一切不要で、コマンドはただ機能しました。少し手の込んだ悪意のあるスクリプトは、同じ技術を使用してシステムファイルを変更または流出させたり、cronジョブやその他の厄介なものをインストールしたりする可能性があります。すべてユーザーに気づかれずにです。
さて、嘘はつきたくありません。上記のroot権限昇格攻撃は、すべてのDockerインストールで機能するわけではありません。Dockerの基本的なインストールを行う場合、デフォルトのインストールではdockerコマンドはrootユーザーのみがアクセスできるため、「root権限昇格」はあまり意味がありません。通常のユーザーアカウントからDockerを使用したい場合は、sudo dockerを実行する必要があり、それには認証が必要です。これらの種類の攻撃は、利便性のためにDockerソケットへのアクセス権限を緩和することが多いため可能です。人々がよく行う非標準の設定変更は、自分自身をマシンのdockerグループに追加することです。これにより、sudoなしでdockerコマンドを実行できるようになります。これが、私が上記で共有したデモンストレーションで行ったこと、そして冒頭で言及したLinuxディストリビューションがユーザーに通知せずに実行したことです。
真実は、rootユーザーとしてのみDockerを使用することは信じられないほど不便であるということです。公式Dockerウェブサイトには、セキュリティの悪夢であるにもかかわらず、sudoなしで動作するように再設定する方法の詳細が記載されています。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システムに存在するリスクと同様のリスクが存在する可能性があります。この点について共有したいことがある場合は、ぜひお聞かせください。
代替手段:rootlessコンテナ
前述のように、Dockerはクライアント-サーバーアーキテクチャを選択しましたが、これは主に従来のroot所有のデーモンにつながりました。しかし、rootユーザーに依存しないコンテナを実行する代替方法があります。多くの代替プラットフォームの中で、2つを挙げたいと思います。
Dockerのrootlessモード:標準Dockerのインストールプロセスのバリエーションで、デーモンはユーザーレベルのサービスとして実行されます。
Podman:デーモンレスコンテナプラットフォーム。
rootless Dockerソリューションは少しハック的だと感じます。公式のインストール手順では、通常のインストールを行い、Dockerデーモンを無効にし、最後に提供されたスクリプトを実行して現在のユーザーのユーザーレベルデーモン置換を作成するように求められます。
Podmanの場合、インストールするだけで完了します。さらに、システムでバックグラウンドサービスを実行する必要がないという利点があります。podmanをdockerの代わりにタイプすることに慣れる(またはシェル設定にalias docker=podmanを追加する)と、ワークフローの大部分は同じように機能する可能性が高いですが、すべてのコンテナは自分のユーザーの下で実行され、root権限昇格の実行可能なパスはありません。そして、デーモンを実行しません(必要ない限り、以下を参照)。
Podmanの落とし穴
Podmanのどこが気に入らないのでしょうか?完璧に見えますが、Dockerが初期から悩まされてきたセキュリティ問題を解決しています。さて、上記の「ワークフローの大部分」がPodmanでDockerと同じように機能すると慎重に述べたことに注意してください。真実は、すべてのワークフローが透過的に切り替えられるわけではないということです。移行中に経験した問題点をいくつかレビューしましょう。
Dockerは、イメージをプルする際にデフォルトで独自のDocker Hubレジストリを使用しますが、Podmanは設定方法によってはそうでない場合があります。次のコマンドを考えてみましょう。
docker pull postgres
これは、Podmanがイメージをどこからプルするかを知らない可能性があるため、Podmanでは失敗する可能性があります。Docker Hub(または使用する他のレジストリ)をデフォルトレジストリとして設定することは可能ですが、Podmanを使用する場合は、すべてのコンテナイメージに完全修飾アドレスを付けて名前を付けるのが最善だと考えています。
podman pull docker.io/library/postgres
また、デーモンレスであるため、Podmanにはいくつかの顕著な違いがあります。デーモンがないため、Podmanは再起動後にコンテナを再起動できません。そのため、24時間年中無休で稼働する必要があるサーバーでPodmanを使用するには、追加の作業が必要です。Podmanには、コンテナを個別のサービスとしてインストールできるpodman quadletコマンドグループとのsystemd統合が含まれています。また、同様に、デーモンがない場合、アプリケーションはAPIを通じてコンテナを起動または対話する方法はどうなりますか?これは実際にはDockerを使用する非常に一般的な方法です。このために、PodmanはオプションのAPIサービスを提供しています。