クラウド環境
外部公開されたKubernetesクラスタのセキュリティを分析
クラウドネイティブ・ツールによってシステムや組織の情報が漏洩される危険性について、オンライン検索サイト「Shodan」を用いて調査したところ、Kubernetesクラスタ(K8s)について懸念すべきデータを確認しました。
クラウドネイティブ・ツールによってシステムや組織の情報が漏洩される危険性について、オンライン検索サイト「Shodan」を用いて調査したところ、Kubernetesクラスタ(K8s)について懸念すべきデータを確認しました。具体的には、インターネットに公開された状態のKubernetesクラスタが、Shodan上で243,469件も見つかりました。さらに、これらのクラスタでは、kubeletサービスのデフォルトポート(10250)も公開されていました。

今回の検索データは比較的最近得たものであり、また、件数の期間別推移を調べたところ、図2に示されるように、大半のデータは本稿執筆から遡って1年未満の間、つまり2021年7月以降に出現したことが分かりました。さらに、Shodan上で得たデータを分析し、Kubernetesクラスタ上でデフォルトのkubelet用ポート(10250)をインターネットに公開している上位10組織を特定しました。
kubelet
kubeletはクラスタのノード上で稼働するエージェントであり、ノードが管理するポッド内で、全てのコンテナを正常に稼働させるためのコントロール機能を提供します。また、ノードのあらゆる設定変更を取り扱い、主要な機能として下記3種が挙げられます。
- ノードをKubernetesクラスタに追加
- ノード内におけるコンテナの起動とヘルスチェック
- ノードの状態などに関する最新情報をコントロール・プレーンに提供
以上の点を踏まえると、昨年にも報告したように、サイバー犯罪者は、暗号資産マイニングツールをKubernetesクラスタ上に不正インストールする足がかりとして、このkubelet APIを狙う可能性があります。また、このようにコンテナ管理の機能を不正使用して内部でコマンドを実行する手口は、攻撃手法のナレッジベース「MITRE ATT&CK」上で、テクニックの1つである「T1609:Container Administration Command(コンテナ管理コマンド)」として定義されています。トレンドマイクロで共有した調査データも、当該のナレッジベースに反映されています。
kubelet API
kubelet APIは、デフォルトでポート番号10250を使用します。本ポートは、クラスタのAPIサーバおよびコントロール・プレーン、ワーカーノードを含む全ノード上で使用されていますが、通常、その公開先は内部サービスに限定され、外部からのアクセスはできません。一方、他の認証手段でブロックされていないkubelet APIエンドポイントへのリクエストは、デフォルトでは匿名のリクエストとして扱われます。kubeletの仕様は文書化されていませんが、主要なAPIエンドポイントの1つである「/runningpods」は、当該kubeletが属するノード内で稼働している全てのポッド情報を返します。 また、「/run」を用いると、ポッド内でコマンドを直接実行することが可能です。上記以外のkubelet APIエンドポイントに関する情報として、オープンソースツール「kubeletctl」が参考として役立ちます。「kubectl」がKubernetes APIへのクエリ作成をサポートするように、「kubeletctl」はkubelet APIへのクエリ作成をサポートします。
Shodanから取得したデータの分析
インターネットにkubeletを公開しているKubernetesクラスタの数を踏まえ、特に、下記の2つ観点から分析を行いました。
- kubeletを経由して情報が取得できるクラスタがどれだけ存在するか
- kubeletを経由した攻撃に対して実際に脆弱性を持つものがどれだけ存在するか
そこで、Shodanの検索結果をダウンロードし、kubelet APIへの匿名リクエストに応答するクラスタを特定しました。検索結果として提供されているIPアドレスを用い、実際にkubelet APIにリクエストを送信するための簡易なスクリプトを作成して実行したところ、公開されているKubernetesノードやkubeletから興味深いデータが得られました。まず、240,000を超える公開状態にあるKubernetesノードのうち、その大半は、匿名リクエストに対してHTTPステータスコード401(unauthorized:認証失敗)を返すか、リクエスト自体が目的のノードに到達しないかのどちらかでした。
401を返すノードのAPIにブラウザからアクセスした場合、下記のような画面が表示されるでしょう。この表示内容自体は、未承認の認証トークンでAPIにアクセスした際の応答として、適切なものです。
一見すると、この結果は、匿名リクエストが拒否された点で期待通りと言えます。しかし、もし攻撃者がkubeletの認証トークンを窃取、改ざんするなどした場合、当該クラスタは危険な状態に置かれるでしょう。さらに、この画面が表示されただけでも、対象のIPアドレスで確かにKubernetesクラスタが稼働していることがわかってしまいます。これをきっかけとして、攻撃者がさまざまな手口や脆弱性を突いた攻撃を画策する可能性があります。
図5で示されるように、約76,000件のリクエストについては、10秒間のタイムアウトか、対象ポートへの接続拒否により、応答が一切得られませんでした。クラスタの状態は永続的なものではなく、ノードは要求に応じて適宜作成、破棄されるため、この結果に問題はないと考えられます。
約3,500のサーバからは、一般的な認証失敗を表す401ではなく、403(Forbidden:アクセス禁止)が返されました。この応答は、認証されていないユーザとしてkubelet APIにリクエストを送ること自体は可能であるが、指定された当該のエンドポイントにアクセスする権限は付与されていなかったことを示します。下図の記載からも、匿名ユーザ(user=system:anonymous)では、稼働中のポッド情報(verb=get, resource=nodes)にアクセスする権限がないことが読み取れます。
最後に、ステータス200(正常)を返したサーバも、他と比べて少ないながら確認されました。このステータスは、当該ノードで稼働するポッドに関する情報がkubelet APIを経由して確かに取得できたことを示します。ポッドの情報はJSON形式で記述され、その内容として、各ポッド名、クラスタ内で稼働しているポッドに対応するネームスペース、ポッド内でどのコンテナが稼働しているか、などの項目が挙げられます。各ポッド内で稼働するコンテナは1つ、または複数の場合もあります。下図に、稼働中のポッドやコンテナに関する情報を、公開状態のkubeletから実際に取得した例を示します。
上記のkubelet APIエンドポイントから取得したポッドに対し、今回の調査では、いかなるコマンドも実行しませんでした。しかし、エンドポイント「/runningpods」が成功したことを踏まえると、例えば「/run」を用いてコマンドを実行できる可能性は、かなり高いと推測されます。その場合、攻撃者は、kubelet APIを使用するだけで、不正なプログラムを当該ポッドに直接インストール、実行できる可能性があります。実際に、これと同等のことが昨年に報告した攻撃グループ「TeamTNT」による複数クラスタを標的とした攻撃事例で確認されています。しかし、今回の発見では、kubelet APIエンドポイントへのリクエストが外部から発生する点において、攻撃者にとってはより一層有利な状況になることが懸念されます。
kubeletの保護
以前にも報告した通り、公開状態のkubeletを見かけることは、もはや珍しいことではなくなりました。しかし、今回のように、ただ1度の検索でこれだけ多数のノードが発見されたのは、初めてのことです。こうしたノード上で公開されたままのkubelet APIエンドポイントを発見した攻撃者は、それを利用してさまざまなポッド情報の窃取に成功し(ステータスコード200)、続いて暗号資産マイニングツールなどの不正なポッドをデプロイする権限を掌握する可能性があります。この他にも、機密情報や認証情報を窃取するポッドをインストール、あるいは、ノード全体が削除されてしまう可能性もあるでしょう。今回の検証では、倫理的な観点から、こうした攻撃の実証確認は行いませんでした。
kubeletの安全性を高める対策として、クラウドサービスプロバイダー(CSPs)側は、アクセス可能なkubeletを公開している企業や組織をバージョン管理情報などによって識別し、注意喚起を行うことで、サービスとしての安全性を高めることが期待できます。一方、企業や組織側では、kubeletがアクセス可能な状態で公開されるような事態を避けるため、以降に述べる「ユーザ認証」と「アクセス権限」の設定について検討することを推奨します。
- kubeletのユーザ認証設定を有効にする。Kubernetesの公式文書によると、デフォルト設定のkubelet APIは、匿名ユーザからのリクエストも正常なものとして取り扱う(他の認証機能によってブロックされていない限り)。そのため、kubeletを起動する際にオプション「<--anonymous-auth=false>」を指定して、匿名ユーザからのアクセスを拒否することを検討する価値がある。このオプション指定により、匿名ユーザからのアクセスを拒否するだけでなく、未認証のいかなるユーザから来たリクエストに対しても、ステータスコード401(Unauthorized:認証失敗)を返すことが可能になる。この他にも、Kubernetesの公式資料にkubeletの認証設定に関する推奨事項が記載されている。
- kubeletのアクセス権限設定を有効にする。デフォルト設定において、kubelet APIへのリクエストは、ユーザ認証さえ通過すれば、目的とするリソース自体へのアクセス権も自動的に得られる。これは、デフォルトにおいて、アクセス権限が「AlwaysAllow:常に許可」に設定されているためであり、APIに対する全てのリクエストが許可される。これに対し、アクセス権限設定を有効にすれば、ユーザやサービスアカウント毎に、アクセス可能なHTTPメソッド、またはエンドポイントを個別に指定することが可能になる。もし認証に成功しても、目的とする特定のリソースをアクセスする権限が当該ユーザにない場合、ステータスコード403(Forbidden:アクセス禁止)が返される。この他にも、Kubernetesの公式資料にkubeletのアクセス権限設定に関する推奨事項が記載されている。
- 不正行為を目論む攻撃者が、コンテナ領域を超えてkubelet認証情報を窃取するような事態が起こらないように、アクセス権限を制限する。
- kubelet証明書を期間毎に更新する。インスタンスの有効期間が短ければ、万が一、攻撃者による侵入が発生した際にも、攻撃の被害や影響の軽減が見込める。
参考記事:
• 「The Fault in Our Kubelets: Analyzing the Security of Publicly Exposed Kubernetes Clusters」
By: Magno Logan
翻訳:清水 浩平(Core Technology Marketing, Trend Micro™ Research)