This post is also available in: English (英語)
概要
2020年12月4日、Kubernetes Product Security Committeeは新たなKubernetesの脆弱性を公開しました。この脆弱性には識別番号 CVE-2020-8554 が付与されています。この脆弱性はすべてのKubernetesバージョンに影響する深刻度が中程度の問題で本稿の公開時点 (日本時間 2020年12月22日午前09:30) ではパッチが提供されていません。CVE-2020-8554は設計上の欠陥で、これによりKubernetesサービスは、任意のIPアドレスに、クラスタトラフィックを傍受させられるようになります。サービスを管理できるユーザーは、この脆弱性を悪用することで、クラスタ内のポッドとノードに対して中間者 (man-in-the-middle、MITM)攻撃を実行できます。
攻撃者はMITM攻撃を利用し、内外のエンドポイントになりすましたり、ネットワークトラフィックから資格情報を収集したり、被害者のデータを意図した送信先への送信前に改ざんしたり、特定IPアドレスとの通信を完全にブロックしたりする可能性があります。トランスポート層セキュリティ(TLS)などの暗号化プロトコルを使用すれば攻撃者はトラフィックに簡単にアクセスできなくなるので、これは対策となります。
マルチテナントクラスタは最もリスクが高くなります。なぜならマルチテナントクラスタにはサービスを管理できる管理者以外のユーザーのいる可能性が高いためです。一ヶ所でテナントを侵害した攻撃者は、本脆弱性を悪用して、クラスタ内のべつのテナントに対するMITM攻撃を実行する可能性があります。
Kubernetes Product Security Committeeは、CVE-2020-8554にパッチを適用するとKubernetes機能の一部に変更が生じると判断したことから、短期的にはこの脆弱性を解決する予定は立っていません。その代わり、脆弱な機能へのアクセスを制限する緩和策が推奨されています。カスタムアドミッションコントローラないしOpen Policy Agent (OPA) Gatekeeperのルールを使う方法です。パロアルトネットワークスのPrisma Cloudコンピューティングをご利用のお客様は、OPAルール用の組み込みアドミッションサポートを通じ、これらの緩和策を有効化することができます。その手順については本稿巻末の「Prisma Cloudコンピューティングによる緩和策」セクションを参照してください。
脆弱性
CVE-2020-8554は、Kubernetes Serviceの内の2つの機能、External IPsとLoad Balancer IPsの設計上の欠陥に起因しています。Kubernetes Servicesとは、一連のポッドで実行されているアプリケーションをネットワークサービスとして公開するための抽象的な方法で、サービスは1つ以上のIPで公開されます。デプロイされると、クラスタ内のノードは、サービスを構成するバッキングポッド(サービス提供をサポートしているポッド)のいずれか1つにサービスIP宛てのトラフィックをルーティングします。
クラスタによってサービスIPを管理・割り当てている場合はとくに問題は起こりませんが、Kubernetesユーザーがサービスに任意のIPを割り当てることができる場合には問題が起こります。この場合、悪意のあるユーザーが、他のエンドポイント(内部・外部)ですでに使用されているIPを割り当てることにより、それらのIPでクラスタのトラフィックすべてを傍受できる可能性があります。サービスのIPを制御する方法は2つあります。
- 外部IPを割り当てる方法
- status.loadBalancer.ingress.ipフィールドにパッチを適用してLoad Balancer IPを割り当てる方法。この方法の場合、patch service/status パーミッションが必要です。
以下のサービスがクラスタにデプロイされた場合、IPアドレス8.8.8.8 (GoogleのDNSサーバー) 宛のすべてのクラスタDNSのトラフィックを傍受してevil-dns-serverポッドにルーティングします。
傍受したトラフィックを受信するには、攻撃者は悪意のあるサービスをバッキングしているエンドポイントを自身の制御下に置いている必要があります。ほとんどの場合、これは上記のサンプルに示したevil-dns-serverのようなポッドになります。クラスターポッドではなく、外部エンドポイントでサービスをバッキングすることもできます。つまり攻撃者は、クラスタ外の外部エンドポイントに傍受したトラフィックをルーティングすることができます。そのためには攻撃者はcreate endpointの特権を持ち、それによって外部アドレスを指すKubernetesエンドポイントを作成できる必要があります。
影響を受けるかどうかを確認するには
この脆弱性はすべてのKubernetesバージョンに影響します。また現時点ではパッチが提供されていません。次の条件を満たす場合、そのクラスタは影響を受けます。
- 管理者以外のKubernetesユーザーがサービスを作成・更新したり、サービスのステータスにパッチを適用したりできるようになっていること AND
- それら特権を持たないユーザーにポッドの制御を許可していること(ポッド作成・更新・実行) OR
- それら特権を持たないユーザーにエンドポイントの作成・更新を許可していること
マルチテナントクラスタは最もリスクが高くなります。なぜなら上記のような脆弱な構成にしている可能性が最も高いためです。マルチテナントクラスタはその多くがKubernetes名前空間を使ってテナントを分離することにより各テナントのアクセス許可をその名前空間内に制限しています。残念ながら、テナントが管理可能なのは自身の名前空間内のサービスとポッドのみであっても、CVE-2020-8554を悪用することで、クラスタ全体のトラフィックが盗聴可能となります。一ヶ所でテナントを侵害した攻撃者は、この脆弱性を悪用して他のテナントのトラフィックを傍受し、侵害する可能性があります。
なお、Ciliumでkube-proxyを置き換えているクラスタはまったく影響を受けません。
CVE-2020-8554のIoC (侵害の痕跡)
次のいずれかに該当する場合、攻撃を受けていた可能性があります。
- external IPsやLoad Balancer IPsを公開すべきではないサービスでこれらが公開されてしまっている。
- サービスのexternal IPsまたはLoad Balancer IPsが、そのクラスタ内の内部IP(ポッドIPまたは別サービスのclusterIP)と合致している。
- サービスのexternal IPsまたはLoad Balancer IPsが、既知の外部ドメイン(8.8.8.8など)を指している。nslookup を実行し、既知のドメインを指しているIPアドレスの有無を識別してください。
- サービスのLoad Balancer IPsが「127.0.0.1」になっている (ノードのlocalhostトラフィックをハイジャックする試みを示すもの)。
external IPsを公開しているクラスタ内のサービスを識別するには次のコマンドを実行します。
1 |
kubectl get services –all-namespaces -o=jsonpath='{“NAMESPACE\tNAME\tEXTERNAL IPS\n”}{range .items[?(.spec.externalIPs)]}{.metadata.namespace}{“\t”}{.metadata.name}{“\t”}{.spec.externalIPs}{“\n”}{end}’ | column -t -s “$(printf ‘\t’)” |
Load Balancer IPを公開しているクラスタ内のサービスを識別するには次のコマンドを実行します。
1 |
kubectl get services –all-namespaces -o=jsonpath='{“NAMESPACE\tNAME\tLOAD BALANCER IPs\n”}{range .items[?(.status.loadBalancer.ingress[*].ip)]}{.metadata.namespace}{“\t”}{.metadata.name}{“\t[“}{range .status.loadBalancer.ingress[*]}{“\””}{.ip}{“\”,”}{end}{“]\n”}{end}’ | sed ‘s/\(.*\),/\1/’ |column -t -s “$(printf ‘\t’)” |
回避・緩和策
Kubernetes Product Security Committee は、この脆弱性にパッチを適用すると、Kubernetesのユーザーが依存する機能への変更が避けられないと結論付けました。そこで、パッチを適用する代わりに脆弱な機能へのアクセスを制限する緩和策を実施することを推奨しています。external IPsの使用を防ぐため、Kubernetes Product Security Committee は2つのソリューションを提供しています。それがカスタムアドミッションコントローラとOPA Gatekeeperの制約です。
Load Balancer IPの緩和策は提供されていません。ただし、Load Balancer IPを使って本脆弱性を悪用するには、patch service/statusのパーミッションが必要で、これは特権とみなされるものです。このため、特権を持たないクラスタ ユーザーにこのパーミッションを与えていないことを確認してください。通常、サービスのステータスを更新するコンポーネントはシステムコンポーネントなので、サービスのステータスを更新しているユーザーアカウントがあれば疑わしいと考えてください。
結論
CVE-2020-8554はKubernetesサービスの設計に根ざした特異な脆弱性です。クラスタがマルチテナントの場合、または特権を持っていないユーザーにサービスの作成・更新を許可している場合、本脆弱性の影響を受けます。クラスタ内のアプリケーションがTLSによる暗号化通信を強制していない場合、リスクが高くなります。この脆弱性にパッチが適用されていない場合でも、Kubernetes Product Security Committeeの提案する緩和策に従えば、悪用を効果的に防ぐことができます。Prisma Cloudコンピューティングをご利用のお客様は、付録の「Prisma Cloudコンピューティングによる緩和策」セクションのアドミッションルールを有効にして、クラスターを保護することをお勧めします。
付録: Prisma Cloudコンピューティングによる緩和策
Prisma Cloud コンピューティングに組み込みのRegoルールのアドミッションサポートを使用することで、Kubernetes Product Security Committeeの提案する緩和策を実装できます。
外部IPへのアクセスを制限するには
本製品をご利用のお客様は、次の手順でサービスが外部IPを公開するのをブロックするアドミッションルールを設定できます。オプションとして、許可されたIPのホワイトリストを提供することもできます。
1. Prisma Cloudコンピューティングのドキュメントにしたがい、クラスタでアドミッションコントロールを有効にします。
2. 「Mitigation for Kubernetes CVE-2020-8554 – External IPs」ルールテンプレートをダウンロードします。次のコマンドを実行するとルールをダウンロードできます。
1 |
wget https://raw.githubusercontent.com/twistlock/k8s-cve-2020-8554-mitigations/main/PrismaExternalIPs.json |
3. [Defend/Access/Admission]に移動し、[Import]をクリックして、ダウンロードしたルールテンプレートを選択します。以下のダイアログが表示されます。[Add] をクリックします。
4. 外部IPとして使用する特定のIPをホワイトリストに登録するには、図3の概説にしたがいルールを更新します。次のルールは、IPアドレス「203.54.74.83」をホワイトリストに登録しています。
ルールが適用されると、禁止されている外部IPを公開するサービスを設定しようとしたさいにそれが失敗し、[Monitor/Event/Admission audits]でアラートがトリガーされます。
各アラートをクリックするとリクエストの詳細を表示できます。
ロードバランサーIPの疑わしい更新に関するアラート
通常、システムアカウントのみがロードバランサーIPをサービスに割り当てる必要があります。これを行おうとするユーザーアカウントがあれば、それはユーザーによるCVE-2020-8554悪用の試みを示している可能性があります。ご自身のクラスタについてこうした前提が当てはまらないのでないかぎり、以下の手順に従ってアラートに適切なルールセットを適用することをお勧めします。
1. Prisma Cloudコンピューティングのドキュメントにしたがい、クラスタでアドミッションコントロールを有効にします。
2. services/statusをPrisma Cloudコンピューティングのアドミッションwebフックで監視するリソースに追加します。次のコマンドを実行し、Prisma CloudコンピューティングのWebフック構成を更新します。
1 |
kubectl get ValidatingWebhookConfiguration tw-validating-webhook -o json | jq –arg new “services/status” ‘.webhooks[0].rules[0].resources? += [$new]’ | jq ‘. | del(.metadata.resourceVersion) | .webhooks[0].rules[0].resources = (.webhooks[0].rules[0].resources | unique)’ | kubectl apply -f – |
注意: サービス更新オペレーションを行うPrisma Cloud コンピューティングのカスタムアドミッションルールを導入している場合、上記のコマンドを実行後、それらのアドミッションルールにもservices/status更新リクエストが届きはじめます。それらのルールに次の行を追加すればservices/statusリクエストは破棄されます。
1 |
not input.request[“subResource”] |
3. 「Mitigation for Kubernetes CVE-2020-8554 – Load Balancer IPs」ルールテンプレートをダウンロードします。次のコマンドを実行するとルールをダウンロードできます。
1 |
wget https://raw.githubusercontent.com/twistlock/k8s-cve-2020-8554-mitigations/main/PrismaLoadBalancerIPs.json |
4. [Defend/Access/Admission]に移動し、[Import]をクリックして、ダウンロードしたルールテンプレートを選択します。以下のダイアログが表示されます。[Add] をクリックします。
5. 特定アカウントでLoad Balancer IPを構成することが予想される場合は、外部IPルールで実装したIPホワイトリストのやり方を踏襲します。
ルールが適用されると、Prisma Cloudコンピューティングは、Load Balancerサービスのステータスにパッチを適用するユーザーアカウントからのリクエストに対し、アラートを発出します。アラートは[Monitor/Event/Admission audits]に表示されます。各アラートをクリックするとリクエストの詳細を表示できます。