This post is also available in: English (英語)
概要
Prisma CloudチームとUnit 42チームは2022年5月に一般的なKubernetesプラットフォームにおける強力なクレデンシャルの使用に関する調査レポートを公開しました。同レポートは、ほとんどのプラットフォームが特権的なインフラコンポーネントをインストールしており、それらが特権昇格に悪用されるおそれがあることを明らかにしています。本稿公開時点で、同レポートで解説したすべてのプラットフォームが、ノードから管理者への特権昇格問題に対応済みであるとをお伝えできることを嬉しく思います。ただし、サードパーティのアドオンがこの問題をふたたび持ち込む可能性はあります。
KubeCon EUとBlackHat USAで私たちが発表した研究では、「半数のプラットフォームにおいて、全ノードが管理者と同等のクレデンシャルをホストしていることが原因で、いずれかのコンテナをエスケープすればそれがクラスター全体の侵害につながりえた」ということが判明しました。同レポートで解説したプラットフォームの大半が、デフォルトでインフラを非特権化しました。またある1社はオプションのアドオンでインフラを非特権化しました。
権限の剥奪は複雑なことが多く、その解決には決して小さくはない労力が求められることは承知しています。Azure Kubernetes Service (AKS)、AWS Elastic Kubernetes Service (EKS)、Google Kubernetes Engine (GKE)、Red Hat OpenShift Container Platform、Antrea、Calicoの各社がアクセス制御強化に向けて取り組んでくださっていることにこの場を借りて感謝申し上げます。
本稿では、私たちの研究について簡単に振りかえった上で、プラットフォーム各社がKubernetesの特権昇格と強力な権限への対処に向けて実装したさまざまな緩和策を取り上げます。「自社のクラスターのロールベース アクセス コントロール(RBAC) ポスチャー(態勢)を評価してみたい」と思われた読者の皆さんは、Kubernetes用のオープンソースRBACアナライザー、rbac-policeをお試しください。
Prisma Cloudをお使いのお客様は、Cloud Code Security(CCS)モジュールを介し、過剰なRBAC権限をはじめとするKubernetesの設定ミスを、クラスターへのデプロイ前に捕捉できます。ランタイムフェーズでは、組み込みのKubernetes用アドミッション コントローラーを使って、Kubernetesの特権昇格を含めたクラスター内の疑わしいアクティビティに対してアラートを発報するポリシーを適用できます。
関連するUnit 42のトピック | Privilege Escalation, Cloud Security, Kubernetes, Containers, Container Escape |
振り返り: 強力な権限はいたるところに
Kubernetesのマネージドサービス、ディストリビューション、アドオンは、クラスターに一連のシステムPodをインストールすることにより、インフラの管理やネットワーク・DNS・ロギングなどの中核機能の有効化を行っています。一般にこれらのシステムPodはDaemonSet経由でクラスター内の各ノードにデプロイされます。
これらDaemonSetの権限付与が緩いと、強力なクレデンシャルを不用意にクラスター全体に拡散してしまう可能性があります。悪用されれば特権昇格につながりかねません(図1)。
強力なDaemonSetの拡散状況を把握するため、私たちは利用者数の多いKubernetesプラットフォーム(マネージドサービス、ディストリビューション、コンテナー ネットワーク インターフェース(CNI))を分析し、特権的なインフラコンポーネントを特定しました。この結果、 ほとんどのプラットフォームが強力なDaemonSetを実行しており、クラスターの各ノードに特権的なクレデンシャルをインストールしていることがわかりました。
半数のプラットフォームでは、これらのクレデンシャルが管理者と同等の権限を持ち、どれか1つでもコンテナがエスケープされれば、クラスター全体が侵害されるおそれがありました(図2)。
強力なDaemonSetが一般的になった理由は主に3つ考えられます。
- 歴史的にKubernetesクラスターはデフォルトでは安全を確保する設定にされてこなかった
Kubeletのような重要コンポーネントに未認証でアクセスできる環境では、最小特権のRBACポスチャー保持は優先事項ではありませんでした。このころ作られたインフラが、強力なDaemonSetの前例となっています。 - Kubernetesの権限のなかには単純に緩すぎるものがある
つまり多くのオペレーションを許可していということです。「必要だがセンシティブなオペレーション実行能力をあるサービスアカウントに与えること」が、ほかの潜在的に有害なオペレーションを実行する権限を暗黙のうちに与えてしまうことがよくあります。RBACはこういったユースケースの多くに適したモデルではありませんし、本人の何らかの属性とリソースの何らかの属性を照合する属性ベースのアクセス制御モデルの方が理にかなう場合が多いでしょう。 - 無害に見えて実は強力な権限もある
ある権限が無害だと考える人がいるならその付与をためらうこともないでしょう。たとえば、Podのステータス更新能力を付与した場合、ReplicaSetの一部であるPodの削除能力も暗黙裡に付与したことになります。
回避・緩和策
強力なDaemonSetを特定した後、私たちはそれぞれのプラットフォームに連絡を取って緩和策について討議し始めました。各チームからは、この問題についての理解と、解決にむけた非常に前向きな応答がありました。ここ数カ月で緩和策の開発、テスト、デプロイを行いました。そして本稿執筆現在、私たちが確認した特権昇格攻撃はすべて解決済みです。
プラットフォーム各社に取り組んでいただいたおかげで、ノードがデフォルトで管理者ではなくなり、Kubernetesをめぐるセキュリティ情勢はより安全なものとなっています。以下のセクションは、各プラットフォームが自社の製品で確認された強力なDaemonSetの問題に対応するために行ったさまざまなアプローチに焦点を当てて解説します。
権限を剥奪する
リスクのある権限設定に対処する最も簡単な方法はその権限を剥奪することです。多くのプラットフォームが、明示的には必要とされないような、特定のリスクのある権限を特定して削除しました。一部の権限は、一定のresourceNamesやサブリソースにスコープを絞ることで安全性を確保しました。
Ciliumの場合、DaemonSetが正しく動作するのに「Podの削除」権限は明示的には必要でないことを確認してこれを剥奪しました。Openshiftの場合、Software-Defined Network(sdn) DaemonSetから「ノードの更新」権限を剥奪しました。この変更は、この権限に依存する機能を非特権の実装に置き換えることで実現しています。
アドミッション コントロールによる制限
DaemonSetのよくある使用例として、各DaemonSetのPodがローカルにノードを管理するローカルノード管理が挙げられます。残念ながらKubernetesは、あるDaemonSetのPodの権限スコープをそのローカルノードのみに絞ることをサポートしていません。したがって、DaemonSet内のすべてのPodは、自身のローカルノードだけでなく全ノードの管理を認可される必要があります。これにより、あるノードを乗っ取った攻撃者は、ローカルのDaemonSet Podのクレデンシャルを悪用し、ほかのノードを侵害して、クラスター内に侵害を広げられます。
Azure Kubernetes Service (AKS)とAWS Elastic Kubernetes Service (EKS)はいずれも、ローカルノードの更新を必要とするPodを持つDaemonSetを実行していました。残念ながらこの権限の付与のためにKubernetesに組み込まれた唯一の方法は、DaemonSetの全Podにクラスターの全ノードの更新を許可することでした。
あるノードを侵害した攻撃者は、DaemonSetのトークンを悪用してほかのノードにtaintを設定して、Podを盗めるようになります。この攻撃は図3に示すような3段階で行われます。
- クラスター内の感染ノード以外の全ノードにNoScheduleのtaintを追加し、感染ノードがクラスター内で唯一利用可能なノードとなるようにします。
- 標的のPodをホストしているノードにNoExecuteのtaintを追加し、Kubernetesに強制的にこのノードを退避させて中のPodを削除させます。
- Kubernetesは標的のPodを再作成します。これでクラスター内で唯一利用可能なノード(侵害済みノード)にのみそのPodをスケジュールできるようになりました。
AKSとEKSのDaemonSetには「ノードを更新する」権限が必要なので、単純な権限の剥奪は有効な解決策になりませんでした。代わりに両プラットフォームともカスタムのValidatingAdmissionWebhookを使ってこの攻撃を緩和しました。
EKSの場合: オペレーションによる制限
EKSの場合、aws-node DaemonSetは特定ノードの属性の更新は必要でしたが、taintの更新は必要ありませんでした。したがってaws-nodeのPodが意図していないノードへのtaint追加を試みた場合、それは攻撃である可能性が高いということになります。そこでEKSチームはValidatingAdmissionWebhookを実装しました。このwebhookdはノード更新リクエストをインターセプトし、aws-nodeサービスアカウントから発行されたtaint操作の試みをブロックします。その様子は下の図4で確認できます。
AKSの場合: ターゲットによる制限
AKSの場合、もう少し状況が複雑でした。AKSのcloud-node-manager DaemonSetはノードにtaintを設定することがあるため、taintの完全なブロックは有効な選択肢になりませんでした。
正確にいえば、各cloud-node-managerは自身をホストするノードのtaint設定のみを必要としていました。AKSはこれを利用して攻撃を緩和しました。AKSでは、ノードの更新リクエストをインターセプトし、どのcloud-node-manager Podがリクエストを発行したかを特定するValidatingAdmissionWebhookを実装しました。
cloud-node-manager Podが自身をホストしているノード以外のノードを更新しようとした場合、そのリクエストは拒否されます。攻撃者がcloud-node-manager Podのクレデンシャルを悪用しようとすると拒否されます(図5)。
これが正しく機能するには、Admission Webhookが「リクエストを発行したサービスアカウントはどれか」だけでなく、「リクエストを発行したPodはどれか」についても知る必要があります。それを可能にしたのが最近行われたKubernetesの拡張機能、バインド サービス アカウント トークン (Bound Service Account Token)です。
従来のトークンは、そのトークンが表しているサービスアカウントのみを参照していました。現在のPodのサービス アカウント トークンには、トークンの発行先Podを指定するクレームも含まれています。アドミッション コントローラーはそのクレームを使って、あるリクエストがどのPodから発行されたものかを識別できます。
このWebhookは、バインド トークンでDaemonSet Podのノードローカルな権限付与が可能になることを示したよい例です。将来的にはKubernetesがこの機能を組み込みサポートしてカスタムでAdmissionWebhookを書く必要はなくなるかもしれません。
特権的な機能をよそに移す
特権的なタスクを実行するには、クラスター内の誰かが強力なクレデンシャルを持たねばなりません。DaemonSetのクレデンシャルはあちこちに分散しているので、特権的なタスクの実行に最適とはいえません。いくつかのプラットフォームでは、DaemonSetではないPodに特権的なタスクを実行させたり、コントロール プレーン コントローラーを使うことで、強力なDaemonSetの問題に対応しました。そうしておけばDaemonSetのもつ強力な権限を剥奪できます。
たとえば、Dataplane v2を実行しているGKEクラスターでは、anted DaemonSetに特定タスク用のPodとノードの更新権限が与えられていました。これらの権限はリスクが高く、数々の特権昇格攻撃に悪用される可能性があります。Podやノードの更新をコントロールプレーンに任せることで、GKEはanted DaemonSetからこれらの強力な権限を剥奪できました。
推奨される対策
基盤となるKubernetesインフラが適切な権限の境界を維持するよう構成されている場合でも、設定ミスで権限を過剰に付与されたアドオンやアプリケーションがあれば、それらはクラスターに同じ攻撃経路を再導入してしまう可能性があります。以下は、クラスターのRBACポスチャーを強化し、クラスター内の特特権昇格を防ぐベストプラクティスです。
- 最小特権の原則に従う。明示的に必要な権限のみを付与する。可能なかぎり、権限を特定のネームスペース、リソース名、またはサブリソースに絞る。
- Kubernetes Infrastructure-as-Code (IaC) の継続的インテグレーション/継続的デリバリー(CI/CD)パイプラインにガードレールを追加する。これにより開発者が意図せずサービスアカウントに強力な権限を付与するのを防げる。オープンソースIaCスキャナ Checkovは、過剰なRBAC権限を警告するKubernetesチェックを多数サポートしている(図6)。
- RBACポスチャーを定期的に見直す。これにより潜在的脅威や過度に強力なアイデンティティを特定できる。信頼度の低いPodや公開されたPodに強力な権限が付与されないよう確認する。rbac-policeのような自動化ツールの利用を検討する。
- DaemonSetに特権的なクレデンシャルを必要とするタスクを割り当てないようにする。この場合、コントロール プレーン コントローラーやデプロイメントが望ましい。
- 異なる信頼レベルを必要とするリソースやワークロードは異なるネームスペースに隔離する。
- RBACで表現できない権限については、アドミッション コントロールを使ってきめ細かい権限の付与を実装する。可能なら安全なオペレーションの許可リストを実装し、強力なサービスアカウントからの予期せぬ悪意のあるリクエストをブロックする。
- TaintやToleration、Nodeアフィニティルール、Podアンチアフィニティルールなどのスケジューリング制約を使用し、信頼できないノードや一般公開されたノードから強力なPodを隔離する。
業界のベストプラクティスを導入する際は、自社のクラスターの脅威モデルを考慮する必要があります。Kubernetesはプラットフォームを構築するためのプラットフォームですので、クラスターの脅威モデルはそのアーキテクチャによって大きく異なることになります。上記のガイドラインはクラスター内の特権昇格問題に対応するものです。
信頼レベルの異なるクラスターを構築している場合、以下の機能を使用しているとクラスター内の特権が大きな脅威となります。
- 悪意のあるテナントやワークロードをホストしている可能性のあるマルチテナントのクラスター
- 単一クラスター上で異なるチームが作業している
- 大規模クラスターに複数のアプリケーションを展開している
一方、単一のアプリケーション専用の小規模なクラスターを運用している場合は、そのクラスター同士の隔離や外部サービスからの隔離に投資する方が理にかなっています。クラスターが異なる信頼レベルをホストしていなければ、クラスター内での特権昇格を防ぐことは最優先事項ではないはずです。それでも、特権昇格攻撃の検出は侵害の特定に役立ちます。
結論
Kubernetesでの安全なRBACポスチャー維持はプラットフォームにとってもユーザーにとっても複雑です。主要プラットフォームがハードニングしたデフォルトを強制すれば、Kubenetesユーザーは安全なアーキテクチャを採用しやすくなります。
本稿で解説したプラットフォーム各社が、非特権のインフラという難題に正面から取り組み、クリエイティブな実装を考え出し、解決してくださったことに感謝申し上げます。
Kubernetesのユーザーやプラットフォームには、CI/CDパイプラインにおけるRBACの設定ミス検出をCheckovやrbac-policeなどのツールを使って自動化することをお勧めします。マネージドサービスについては、インフラのコンポーネントがリスクの高い権限を必要とする場合でも、ValidatingAdmissionWebhookを使うことで誤った利用を防げるかもしれません。
詳細については、弊社のレポート『Kubernetes Privilege Escalation: Excessive Permissions in Popular Platforms』をご一読ください。Prisma Cloudをお使いのお客様には同レポートの「Prisma Cloud」のセクションをお読みいただいて、PrismaのKubernetes IaCスキャン機能やKubernetes用組み込みアドミッション コントローラーがKubernetesのアイデンティティ保護という課題にどのように取り組んでいるかを知っていただければと思います。