ワークロードを専用ノードプールに分離する


このページでは、特権付き GKE マネージド ワークロードとは別の専用ノードプールでワークロードをスケジュールするように Google Kubernetes Engine(GKE)に指示することで、クラスタ内の権限昇格攻撃のリスクを軽減する方法について説明します。このページは、ノード自動プロビジョニングのない標準クラスタに適用されます。ノード自動プロビジョニングが有効になっている Standard クラスタと Autopilot クラスタでワークロードを分離するには、GKE でワークロードの分離を構成するをご覧ください。

概要

GKE クラスタは、特権付き GKE マネージド ワークロードを使用して、指標の収集などの特定のクラスタの機能と特徴を有効にします。これらのワークロードには、クラスタ内で正しく実行するための特別な権限が付与されます。

ノードにデプロイするワークロードは、悪意のあるエンティティによって侵害されるおそれがあります。特権付き GKE マネージド ワークロードとともにこれらのワークロードを実行すると、不正使用されているコンテナから抜け出した攻撃者が、ノード上の特権付きワークロードの認証情報を使用して、クラスタ内の権限を昇格できるようになってしまいます。

コンテナ ブレイクアウトの防止

主な防御はアプリケーションである必要があります。GKE には、クラスタと Pod を強化するために使用できる機能が複数あります。ほとんどの場合、ワークロードを分離するために GKE Sandbox を使用することを強くおすすめします。GKE Sandbox は gVisor オープンソース プロジェクトに基づいており、ユーザー空間に Linux カーネル API を実装します。各 Pod は、ホスト カーネル内の特権付きシステムコールへのアクセスを防止するため、アプリケーションをサンドボックス化する専用のカーネルで実行します。GKE Sandbox で実行するワークロードは、他のワークロードから分離され、別々のノードで自動的にスケジューリングされます。

クラスタのセキュリティを強化するの推奨事項にも従う必要があります。

権限昇格攻撃の回避

GKE Sandbox を使用できず、他の強化策に加えて分離を強化したい場合は、ノード taintノード アフィニティを使用して、専用ノードプールでワークロードをスケジュールします。ノード taint は、これらのノード上で対応する toleration のないワークロード(GKE マネージド ワークロードなど)のスケジューリングを回避するよう GKE に指示します。独自のワークロードでのノード アフィニティでは、GKE に Pod を専用ノードでスケジュールするよう指示します。

ノード分離の制限事項

  • 攻撃者は、不正使用されたノードからサービス拒否攻撃(DoS)を開始できます。
  • 不正使用されたノードでも、クラスタ内のすべての Pod や Namespace など、多くのリソースを読み取ることができます。
  • 不正使用されたノードは、そのノードで実行されているすべての Pod が使用する Secret と認証情報にアクセスできます。
  • ワークロードを分離するために別々のノードプールを使用すると、コスト効率、自動スケーリング、リソース使用率に影響を与える可能性があります。
  • 不正使用されたノードは、下りネットワーク ポリシーを回避できます。
  • 一部の GKE マネージド ワークロードは、クラスタ内のすべてのノードで実行され、すべての taint を容認するように構成されている必要があります。
  • 昇格した権限を持ち、任意の taint を容認できる DaemonSet をデプロイすると、これらの Pod は不正使用されたノードからの権限昇格の経路になる可能性があります。

ノード分離の仕組み

ワークロードにノード分離を実装するには、次のようにする必要があります。

  1. ワークロードのノードプールに taint とラベルを追加します。
  2. 対応する容認機能とノード アフィニティ ルールでワークロードを更新します。

このガイドでは、クラスタ内で 1 つのノードプールで始めることを前提としています。ノード taint に加えてノード アフィニティを使用することは必須ではありませんが、スケジューリング全体をより制御できるようになるので、そうすることをおすすめします。

準備

作業を始める前に、次のことを確認してください。

  • Google Kubernetes Engine API を有効にする。
  • Google Kubernetes Engine API の有効化
  • このタスクに Google Cloud CLI を使用する場合は、gcloud CLI をインストールして初期化する。すでに gcloud CLI をインストールしている場合は、gcloud components update を実行して最新のバージョンを取得する。
  • 専用ノードプールに使用するノードラベルとノード taint に特定の名前を選択します。この例では workloadType=untrusted を使用します。

ワークロードのノードプールに taint とラベルを適用する

ワークロードの新しいノードプールを作成し、ノード taint とノードラベルを適用します。ノードプール レベルで taint またはラベルを適用すると、自動スケーリングによって作成された新しいノードなど、あらゆる新しいノードは指定された taint とラベルを自動的に取得します。

ノード taint とノードラベルを既存のノードプールに追加することもできます。NoExecute 効果を使用すると、GKE は、新しい taint の容認機能がないノード上で実行されている Pod を強制排除します。

新しいノードプールに taint とラベルを追加するには、次のコマンドを実行します。

gcloud container node-pools create POOL_NAME \
    --cluster CLUSTER_NAME \
    --node-taints TAINT_KEY=TAINT_VALUE:TAINT_EFFECT \
    --node-labels LABEL_KEY=LABEL_VALUE

以下を置き換えます。

  • POOL_NAME: ワークロードの新しいノードプールの名前。
  • CLUSTER_NAME: GKE クラスタの名前。
  • TAINT_KEY=TAINT_VALUE: スケジュールする TAINT_EFFECT に関連付けられた Key-Value ペア。例: workloadType=untrusted
  • TAINT_EFFECT: NoSchedulePreferNoSchedule、または NoExecute のいずれかの効果値NoExecuteNoSchedule よりも強制排除が保証されています。
  • LABEL_KEY=LABEL_VALUE: ノードラベルの Key-Value ペア。ワークロード マニフェストで指定したセレクタに対応しています。

ワークロードに toleration とノード アフィニティ ルールを追加する

専用ノードプールに taint を追加すると、ワークロードは、追加した taint に対応する容認機能がなければ、そのノードプールにスケジュールできなくなります。容認機能をワークロードの仕様に追加して、taint が追加されたノードプールで Pod がスケジュールされるようにします。

専用ノードプールにラベルを付けた場合は、ノード アフィニティ ルールを追加して、GKE にそのノードプールにのみワークロードをスケジュールする指示を行うこともできます。

次の例では、workloadType=untrusted:NoExecute taint に対する toleration と workloadType=untrusted ノードラベルのノード アフィニティ ルールを追加します。

kind: Deployment
apiVersion: apps/v1
metadata:
  name: my-app
  namespace: default
  labels:
    app: my-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      tolerations:
      - key: TAINT_KEY
        operator: Equal
        value: TAINT_VALUE
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: LABEL_KEY
                operator: In
                values:
                - "LABEL_VALUE"
      containers:
      - name: sleep
        image: ubuntu
        command: ["/bin/sleep", "inf"]

次のように置き換えます。

  • TAINT_KEY: 専用ノードプールに適用した taint キー。
  • TAINT_VALUE: 専用ノードプールに適用した taint 値。
  • LABEL_KEY: 専用のノードプールに適用したノードラベルのキー。
  • LABEL_VALUE: 専用ノードプールに適用したノードラベル値。

kubectl apply を使用して Deployment を更新すると、GKE では影響を受ける Pod が再作成されます。ノード アフィニティ ルールにより、作成した専用ノードプール上に Pod を強制移動します。この容認機能によって、それらの Pod のみをノードに配置できます。

分離が機能していることを確認する

スケジューリングが正しく機能することを確認するには、次のコマンドを実行してワークロードが専用ノードプールにあるかどうかを確認します。

kubectl get pods -o=wide

推奨事項とベスト プラクティス

ノード分離を設定したら、次のことをすることをおすすめします。

  • components.gke.io/gke-managed-components taint を追加して、特定のノードプールを GKE マネージド ワークロードのみに制限します。この taint を追加すると、独自の Pod がこれらのノードでスケジュールされなくなり、分離が改善します。
  • 新しいノードプールを作成する場合、独自の taint をこれらのノードプールに追加して、ほとんどの GKE マネージド ワークロードがこれらのノードで実行されないようにします。
  • サードパーティ ツールをインストールする場合など、クラスタに新しいワークロードをデプロイする際は、常に Pod に必要な権限を監査してください。可能であれば、昇格権限を使用するワークロードを共有ノードにデプロイすることは避けてください。

次のステップ