Kubernetes API Serverのバイパスリスク
Kubernetes APIサーバーは、外部の関係者(ユーザーやサービス)がクラスターと対話するための主要なエントリポイントです。
この役割の一環として、APIサーバーには監査ログやアドミッションコントローラーなど、いくつかの重要なセキュリティ制御が組み込まれています。 しかし、これらの制御をバイパスしてクラスターの設定やコンテンツを変更する方法があります。
このページでは、Kubernetes APIサーバーに組み込まれているセキュリティ制御をバイパスする方法について説明します。 これにより、クラスター運用者やセキュリティアーキテクトは、これらのバイパスが適切に制限されるようにできます。
Static Pod
各ノードのkubeletは、特定のディレクトリに保存されているマニフェストや、特定のURLから取得したマニフェストをクラスター内のstatic Podとして読み込み、直接管理します。 APIサーバーはこれらのstatic Podを管理しません。 この場所への書き込みアクセス権を持つ攻撃者は、そのソースから読み込まれたstatic Podの設定を変更したり、新しいstatic Podを導入できます。
Static Podは、Kubernetes API内の他のオブジェクトへのアクセスが制限されています。
例えば、static Podにクラスターからシークレットをマウントするように設定することはできません。
ただし、これらのPodは基盤となるノードからhostPath
マウントを使用するなど、他のセキュリティ上機微な操作を行うことができます。
デフォルトでは、kubeletはミラーPodを作成し、static PodをKubernetes APIに表示します。 ただし、攻撃者がPod作成時に無効なNamespaceを指定した場合、Kubernetes APIには表示されず、影響を受けるホストにアクセスできるツールでのみ発見できます。
static Podがアドミッション制御に失敗した場合、kubeletはPodをAPIサーバーに登録しません。 ただし、Podはノード上で実行され続けます。 詳細については、kubeadm issue #1541を参照してください。
緩和策
- ノードでstatic Pod機能が必要な場合のみ、kubelet static Podマニフェスト機能を有効にする。
- ノードでstatic Pod機能を使用する場合、static PodマニフェストディレクトリまたはURLへのファイルシステムアクセスを必要なユーザーに制限します。
- kubeletの設定パラメーターやファイルへのアクセスを制限し、攻撃者がstatic PodのパスやURLを設定できないようにします。
- static Podのマニフェストとkubeletの設定ファイルをホストするディレクトリやwebストレージのロケーションへのすべてのアクセスを定期的に監査し、一元的にレポートします。
kubelet API
kubeletは、通常クラスターのワーカーノードのTCPポート10250で公開されるHTTP APIを提供します。 APIは、使用しているKubernetesディストリビューションによっては、コントロールプレーンノードでも公開される場合があります。 APIに直接アクセスすると、ノード上で実行されているPodに関する情報の開示、これらのPodからのログ、おyびノード上で実行されているすべてのコンテナ内でコマンドを実行できます。
KubernetesクラスターユーザーがNode
オブジェクトのサブリソースにRBACアクセスを持つ場合、そのアクセスはkubelet APIと対話するための認可を提供します。
正確なアクセスは、kubelet認証で詳しく説明されているように、付与されたサブリソースアクセスに依存します。
kubelet APIに直接アクセスすると、アドミッション制御の対象にならず、Kubernetesの監査ログにも記録されません。 このAPIに直接アクセスできる攻撃者は、特定のアクションを検出または防止する制御をバイパスできる可能性があります。
kubelet APIは、さまざまな方法でリクエストを認証するように構成できます。
デフォルトでは、kubeletの設定は匿名アクセスを許可します。
ほとんどのKubernetesプロバイダーは、デフォルトをwebhookおよび証明書認証を使用するように変更します。
これにより、コントロールプレーンは呼び出し元がnodes
APIリソースまたはサブリソースにアクセスする権限があることを確認できます。
デフォルトの匿名アクセスでは、コントロールプレーンでこのアサーションは行われません。
緩和策
- RBACなどのメカニズムを使用して、
nodes
APIオブジェクトのサブリソースへのアクセスを制限します。 監視サービスなど、必要な場合にのみこのアクセスを許可してください。 - kubeletのポートへのアクセスを制限します。 指定された信頼できるIPアドレス範囲からのアクセスのみを許可します。
- kubelet認証が、webhookまたは証明書モードに設定されていることを確認します。
- 認証されていない「読み取り専用」Kubeletポートがクラスターで有効になっていないことを確認します。
etcd API
Kubernetesクラスターは、etcdをデータストアとして使用します。
etcd
サービスは、TCPポート2379でリッスンします。
アクセスが必要なクライアントは、Kubernetes APIサーバーと使用しているバックアップツールのみです。
このAPIに直接アクセスすると、クラスター内のデータの開示または変更が可能になります。
etcd APIへのアクセスは、通常クライアント証明書認証によって管理されます。 etcdが信頼する認証局によって発行された証明書は、etcd内に保存されているデータへのフルアクセスを許可します。
etcdに直接アクセスすると、Kubernetesのアドミッション制御の対象にならず、Kubernetesの監査ログにも記録されません。 APIサーバーのetcdクライアント証明書の秘密鍵を読み取る権限を持つ(または新しい信頼できるクライアント証明書を作成できる)攻撃者は、クラスターのシークレットにアクセスしたり、アクセスルールを変更することで、クラスター管理者権限を取得できます。 KubernetesのRBAC特権を昇格させなくとも、etcdを変更できる攻撃者は、任意のAPIオブジェクトを取得したり、クラスター内に新しいワークロードを作成できます。
多くのKubernetesプロバイダーは、相互TLS(クライアントとサーバーの両方が認証のために互いの証明書を検証)を使用するようにetcdを構成します。 etcd APIには広く受け入れられた認可の実装はありませんが、機能は存在します。 認可モデルが存在しないため、etcdへのクライアントアクセス権限を持つ証明書であれば、etcdへのフルアクセスを取得できます。 通常、ヘルスチェックのみに使用されるetcdクライアント証明書も、完全な読み取りおよび書き込みアクセスを付与できます。
緩和策
- etcdに信頼されている認証局は、そのサービスへの認証目的のみに使用されることを確認してください。
- etcdのサーバー証明書の秘密鍵、およびAPIサーバーのクライアント証明書と秘密鍵へのアクセスを制御します。
- 指定された信頼できるIPアドレス範囲からのアクセスのみを許可するように、ネットワークレベルでetcdポートへのアクセスを制限することを検討してください。
コンテナランタイムソケット
Kubernetesクラスターの各ノードでは、コンテナと対話するためのアクセスはコンテナランタイム(1つ以上のランタイムを構成している場合はそれらのランタイム)によって制御されます。 通常、コンテナランタイムはkubeletがアクセスできるUnixソケットを公開します。 このソケットにアクセスできる攻撃者は、新しいコンテナを起動したり、実行中のコンテナと対話できます。
クラスターレベルでは、このアクセスの影響は、侵害されたノードで実行されているコンテナが、攻撃者が他のワーカーノードやコントロールプレーンのコンポーネントに特権を昇格されるために使用できるシークレットやその他の機密データにアクセスできるかどうかによって異なります。
緩和策
- コンテナランタイムソケットへのファイルシステムアクセスを厳密に制御してください。
可能であれば、
root
ユーザーにこのアクセスを制限してください。 - Linuxカーネルの名前空間などのメカニズムを使用して、ノード上で実行されている他のコンポーネントからkubeletを分離します。
- コンテナランタイムソケットを含む
hostPath
マウントの使用を、直接または親ディレクトリをマウントすることによって制限または禁止してください。 また、攻撃者がディレクトリ制限をバイパスするリスクを軽減するために、hostPath
マウントは読み取り専用として設定する必要があります。 - ノードへのユーザーアクセスを制限し、特にノードへのスーパーユーザーアクセスを制限してください。