This post is also available in: English (英語)
概要
クラウドコンピューティングの発展に伴いコンテナ人気はますます高まっており、コンテナ実装方法のソリューションやアイデアが新たに導入されはじめています。そうした新しいアイデアの1つがrootlessコンテナです。
rootlessコンテナはコンテナの新しい概念で、編成のさいroot権限を必要としません。権限のないユーザーがコンテナを作成する上での技術的課題を克服するために多くのソリューションが提案されており、その中には開発中のものもあればすでに本番環境に対応しているものもあります。ただし(主にセキュリティ上のメリットはあるものの)rootlessコンテナはまだその形成期にあると言えるでしょう。
本稿では、Unit 42のリサーチャーである筆者Aviv Sassonが、rootlessコンテナの内部をレビューし、つづいてrootlessネットワーク接続機能の主要コンポーネントの1つ(Slirp)で見つけた脆弱性について説明します。パロアルトネットワークスのPrisma Cloudを実行しているお客様は、ホストおよびコンテナの脆弱性スキャナによりこの脆弱性から保護されています。このスキャナは、実行しているソフトウェアコンポーネントに本脆弱性が含まれている場合に警告を表示します。
背景
rootlessコンテナはその名が示すとおり編成にroot権限がいらない点をのぞいては従来のコンテナとかわりません。
現在のrootlessコンテナはまだ導入初期段階ですが、すでに主要なコンテナ開発元によるサポートもはじまっています。
rootlessコンテナが登場した理由はいくつかあります。
- 新たなセキュリティレイヤを追加するため。コンテナエンジン、ランタイム、オーケストレータなどに不正アクセスされても攻撃者はホスト上のroot権限を取得できない。
- 複数の非rootユーザーが同じマシン(HPCなど)でコンテナを実行できるようにするため。
- ネストされたコンテナ内での分離を可能にするため。
このソリューションはLinuxカーネルの新たな進展であるユーザ名前空間によって可能になったもので、そこでは非rootユーザーが新しいユーザー名前空間を作成することができます。新しいユーザー名前空間を作成してその名前空間に入ると、当該ユーザーはその名前空間におけるrootとなり、機能するコンテナの生成に必要な権限のほとんどを取得できます。
ユーザー名前空間の専門的技術についてここで掘り下げて説明はしませんが、ユーザー名前空間のrootには、システム全体に影響する実rootほどの特権はありません。たとえばユーザー名前空間のrootではカーネルモジュールのロードや削除ができません。ここから生じる問題については、コンテナエンジンごとに異なる対処が取られています。
ネットワーク接続
コンテナ内でネットワーク接続するのに、通常は仮想イーサネットデバイス(veth)が作成され、それがネットワーク接続を管理します。ただしこうしたデバイスの作成権限を持つのは実rootだけなので、rootlessコンテナの場合はここがネックになります。この問題を解決するためにさまざまなソリューションが提案されていますが、その主なものがSlirpとlxc-user-nicです。
Slirp
Slirpはもともと主にQEMU(別名Quick Emulator)のネットワーク接続に使用されていた有名プロジェクトです。いくぶんの変更を加え、rootlessコンテナでのネットワーク接続が可能になるように修正されました。Slirpはコンテナのユーザー名前空間、ネットワーク名前空間へのフォーク処理と、デフォルトのルートになるTAPデバイスの作成によって機能します。Slirpは次に、デフォルトのネットワーク名前空間で動作している親にデバイスのファイル記述子を渡します。これによりコンテナとインターネットの両方と通信できるようになります。
lxc-user-nic
Slirp以外にネットワークの接続設定を行う方法として、vethデバイスを作成するsetuidバイナリを実行するというやりかたもあります。ただしlxc-user-nicはコンテナ内でのネットワーク接続は可能にしてくれるものの、コンテナバイナリをroot権限で実行する必要があることから、その特性上、rootlessコンテナには向いていません。
ストレージ
コンテナ実装で難しい要素の1つにストレージ管理があげられます。デフォルトだとコンテナエンジンはOverlay2(またはOverlay)と呼ばれる特別なドライバを使用し、スペースの利用、性能の両面で効率の良い階層型ファイルシステムを形成します。ほとんどのLinuxディストリビューション(Ubuntuは除く)では、ユーザー名前空間でのOverlayファイルシステムのマウントを許可していないため、rootlessコンテナでは階層型ファイルシステムの作成ができません。この問題により、他のドライバやファイルシステムとrootlessコンテナとの連携が促進されました。
自明な解決策はVFSストレージドライバなど別のドライバを使用することでしょうが、このドライバはうまく動きはするものの、効率が大幅に低下します。より適切な解決策はrootlessコンテナのニーズに合う新しいストレージドライバを作成することで、そうしたドライバの1つがFUSE-OverlayFSです。このドライバはOverlayのユーザー空間実装なのでVFSよりも効率的でユーザー名前空間での実行も可能です。
cgroups
Linux control group(cgroups)機能もコンテナ実装上の重要要素の1つで、プロセスとコンテナを階層グループにまとめ、そのさまざまな種類のリソースの使用を制限・監視することができます。ただしカーネルのcgroupsインターフェイスは通常「/sys」(root所有ディレクトリ)にある疑似ファイルシステムを介して提供されるるので非rootユーザーはcgroupsインターフェイスにアクセスして使用することができません。
この問題に対応するため、次の2つのアプローチが提案されました。
cgroups V2
cgroupsの新しいカーネル実装で、非rootユーザーへのアクセス許可の委任をサポートします。ただしcgroups V2ではV1用に実装されたコントローラ(devices、net_cls、net_prioなど)の一部しかサポートしていないのが難点です。
PAMモジュール
LXCによるもう1つの解決策がpam_cgfs.soのインストールです。pam_cgfs.soは、非rootユーザーがcgroupsを認証・管理できるようにするPluggable Authentication Module(PAMモジュール)です。
導入状況
以下のコンテナエンジンでは、次にあげるコンポーネントを備えるrootlessコンテナをサポートしています。
Docker | Podman | LXC | |
ネットワーク接続 | – Slirp – lxc-user-nic – VPNkit |
Slirp | lxc-user-nic |
ストレージ | VFS | FUSE-OverlayFS | VFS |
cgroups | サポートなし | cgroups v2の制限付きサポート | PAMモジュール |
表1. 導入状況
上記の表からもわかるとおり、PodmanとLXCに先導されるかたちで、代表的コンテナエンジンがrootlessコンテナのさまざまな側面のサポートに取り組みはじめています。
セキュリティ
セキュリティ上、rootlessコンテナの使用には大きなメリットがあります。セキュリティの世界では、すべてのソフトウェアは脆弱性や間違った構成(コンテナの実装を含む)が原因で不正使用される可能性があることを前提としています。私たちは常に、可能な限り権限を制限してソフトウェアを実行せねばなりません。そうすることでセキュリティ上の不具合が悪用された場合でも、影響を最小限に抑えることができるのです。
rootlessコンテナの安全性は高いはずですが、これまで広くテストやレビューをされたことのない新しい機能やコンポーネントが利用されています。こうしたコンポーネントは、気付かぬうちに別の攻撃ベクトルになる可能性があります。その一例として、rootlessコンテナのネットワーク接続ソリューションがあります。lxc-user-nicもSlirpもコンテナとホストの両方に影響するセキュリティ上の脆弱性をはらんでいる可能性があります。
lxc-user-nicにはCVE-2017-5985、CVE-2018-6556など、特権昇格が可能な脆弱性が複数見つかりました。もう1つの例はSlirpです。近年、ホストでのコード実行につながる可能性のあるヒープオーバーフローなど、複数の脆弱性が明らかになりました。完全な乗っ取りを回避するため、Slirpのメンテナはソフトウェアにサンドボックス機能とseccompのサポートを追加しました。ただ実際には、seccompサポートはまだ実験段階でサンドボックスをエスケープできる可能性があるため、コンテナエンジンはseccompサポートなしでSlirpを実行しています。
Slirp – CVE-2020-1983
筆者は調査の一貫として、潜在的脆弱性の検出・修正のためにSlirpの独自調査を行いました。このために同ソフトウェアをファジング中、Slirpをクラッシュさせる可能性のあるuse-after-free脆弱性が特定されました。この脆弱性にはCVE-2020-1983が割り当てられました。
この問題はSlirpがIPフラグメンテーションを管理する方法に関係しています。IPパケットの最大サイズは65,535バイトなので、フラグメント化する場合、この値が上限となるはずです。今回特定された不具合は、Slirpがフラグメント化されたIPパケットのサイズ検証を行っておらず、65,535バイトより大きいパケットをフラグメント化しようとするとクラッシュする、というものです。
Slirpが停止するとコンテナはネットワークスタックを失うため、実質的に使用することができなくなります。
なお、libslirpのその他の脆弱性により、単なるクラッシュにとどまらず、コンテナでのコード実行が発生する可能性もあります。また最終的にはコンテナからホストおよびその他のコンテナへのブレイクアウトが発生する可能性もあります。2020年にはそうした脆弱性が2件見つかっています(CVE-2020-8608とCVE-2020-7039)。
筆者は本件についてセキュリティ上のアドバイスをSlirpの開発チームに伝えました。これを受け、修正パッチを迅速に公開してくださったSlirpの開発チームの皆さんにお礼を申し上げます。影響を受けるSlirpバージョンは4.0.0から4.2.0です。
Prisma Cloudによる保護
パロアルトネットワークスのPrisma Cloudを実行しているお客様は、Prisma Cloudコンピューティングのホストおよびコンテナの脆弱性スキャナによって脆弱性から保護されています。このスキャナは、ソフトウェアコンポーネントにこの脆弱性が含まれている場合に警告を表示します。
結論
コンテナの新しいアプローチ rootlessコンテナは、コンテナに重要なセキュリティレイヤを追加してくれる存在です。rootlessコンテナはおそらくあっさりとクラウド内コンテナの次なるトレンドとなることでしょう。まだまだ多くの制限がありますし、その機能の一部は実験段階や開発段階にありますが、手間と時間を掛ければ、完全な機能をもち、コミュニティに取り入れられるようになっていくでしょう。そうすれば、rootressコンテナが従来のコンテナに取って代わるものと思われます。