このページでは、Google Distributed Cloud(GDC)エアギャップの専用ノードプールでコンテナ ワークロードを分離して、Pod をより詳細に制御する方法について説明します。ワークロードの分離には、次のようなメリットがあります。
- Kubernetes クラスタでの権限昇格攻撃のリスクが軽減されます。
- 追加のリソースを必要とする Pod をより細かく制御できます。
このような場合は、コンテナ ワークロードを分離して、制御と最適化を強化することを検討してください。
ワークロードを分離する理由
ワークロードを専用ノードプールに分離する必要はありませんが、潜在的な問題を回避するための賢明な対策となります。ただし、専用ノードプールの管理にはより多くの監視が必要であり、多くの場合、不要です。
Kubernetes クラスタは、特権付き GDC マネージド ワークロードを使用して、指標の収集などの特定のクラスタ機能と機能を有効にします。これらのワークロードには、クラスタ内で正しく実行するための特別な権限が付与されます。
ノードにデプロイするワークロードは、悪意のあるエンティティによって侵害されるおそれがあります。特権付き GDC マネージド ワークロードとともにこれらのワークロードを実行すると、侵害されたコンテナをブレイクアウトした攻撃者が、ノード上の特権付きワークロードの認証情報を使用して、クラスタ内の権限を昇格できるようになります。
専用ノードプールは、他より多くのリソース(メモリやローカル ディスク容量など)を必要とする Pod をスケジュールする必要がある場合にも役立ちます。
次のメカニズムを使用して、専用ノードプールでワークロードをスケジュールできます。
- ノードの taint - https://cloud.google.com/kubernetes-engine/docs/how-to/node-taints
- ノード アフィニティ - https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes-using-node-affinity/
ノード taint は、これらのノード上で対応する toleration のないワークロード(GDC マネージド ワークロードなど)のスケジューリングを回避するよう Kubernetes クラスタに通知します。独自のワークロードのノード アフィニティは、Pod を専用ノードでスケジュールするようにクラスタに指示します。
ノード分離の制限事項
攻撃者は、侵害されたノードからサービス拒否攻撃(DoS)を開始できます。
侵害されたノードは、クラスタ内のすべての Pod や Namespace など、引き続き多くのリソースを読み取ることができます。
侵害されたノードは、そのノードで実行されているすべての Pod が使用する Secret と認証情報にアクセスできます。
ワークロードを分離するために別のノードプールを使用すると、コスト効率、自動スケーリング、リソース使用率に影響を与える可能性があります。
侵害されたノードは、下りネットワーク ポリシーを回避できます。
一部の GDC マネージド ワークロードは、クラスタ内のすべてのノードで実行される必要があり、すべての taint を許容するように構成されています。
昇格した権限を持ち、あらゆる taint を許容できる
DaemonSet
リソースをデプロイすると、これらの Pod が、侵害されたノードからの権限昇格に利用される可能性があります。
ノード分離の仕組み
ワークロードにノード分離を実装するには、次のようにする必要があります。
ワークロードのノードプールに taint とラベルを追加します。
対応する toleration とノード アフィニティ ルールでワークロードを更新します。
このガイドでは、クラスタ内の 1 つのノードプールから始めることを前提としています。ノード taint に加えてノード アフィニティを使用することは必須ではありませんが、スケジューリング全体をより詳細に管理できるようになるので、ノード アフィニティを使用することをおすすめします。
始める前に
作業を始める前に、次のことを確認してください。
専用ノードプールに使用するノード taint とノードラベルに特定の名前を選択します。例:
workloadType=untrusted
必要に応じて、組織 IAM 管理者に、名前空間にバインドされていないユーザー クラスタ デベロッパー ロール(
user-cluster-developer
)を付与するよう依頼します。
新しいノードプールに taint とラベルを適用する
新しいノードプールに taint またはラベルを適用すると、後で追加されたノードを含むすべてのノードが、指定された taint とラベルを自動的に取得します。
新しいノードプールに taint とラベルを追加する手順は次のとおりです。
ノードプールを作成するときに、
Cluster
カスタム リソースのnodePools
セクションを直接編集します。nodePools: ... - machineTypeName: n2-standard-2-gdc name: nodepool-1 nodeCount: 3 taints: TAINT_KEY=TAINT_VALUE:TAINT_EFFECT labels: LABEL_KEY=LABEL_VALUE
次のように置き換えます。
TAINT_KEY=TAINT_VALUE
: スケジュールするTAINT_EFFECT
に関連付けられた Key-Value ペア。例:workloadType=untrusted
。TAINT_EFFECT
: 次のいずれかの効果値。NoSchedule
: この taint を容認しない Pod はノード上にスケジュールされません。既存の Pod はノードから強制排除されません。PreferNoSchedule
: Kubernetes は、この taint を容認しない Pod をノード上にスケジュールすることを避けます。NoExecute
: ノードですでに実行されている Pod は、ノードから強制排除されます。ノードでまだ実行されていない Pod は、ノード上にスケジュールされません。
LABEL_KEY=LABEL_VALUE
: ノードラベルの Key-Value ペア。ワークロード マニフェストで指定したセレクタに対応しています。
Cluster
リソースを適用して、新しいノードプールを作成します。kubectl apply -f cluster.yaml \ --kubeconfig MANAGEMENT_API_SERVER
MANAGEMENT_API_SERVER
は、Kubernetes クラスタがホストされているゾーン API サーバーの kubeconfig パスに置き換えます。ターゲット ゾーンの API サーバーの kubeconfig ファイルをまだ生成していない場合は、ログインをご覧ください。
既存のノードプールに taint とラベルを適用する
既存のノードプールに taint またはラベルを適用するには、既存の各ノードに変更を適用する必要があります。ノードプール構成を動的に更新することはできません。
既存のノードプールに taint とラベルを追加する手順は次のとおりです。
専用ノードプール内のノードを一覧表示します。
kubectl get node --kubeconfig KUBERNETES_CLUSTER_KUBECONFIG \ -l baremetal.cluster.gke.io/node-pool=NODE_POOL_NAME
次の変数を置き換えます。
KUBERNETES_CLUSTER_KUBECONFIG
: Kubernetes クラスタの kubeconfig パス。NODE_POOL_NAME
: 専用ノードプールの名前。
出力から、ノードプール内のすべてのノードの各ノード ID をメモします。
ノードプール内の各ノードに、次の taint を適用します。
kubectl taint nodes NODE_ID \ TAINT_KEY=TAINT_VALUE:TAINT_EFFECT \ --kubeconfig KUBERNETES_CLUSTER_KUBECONFIG
次の変数を置き換えます。
NODE_ID
: 専用ノードプール内のワーカーノードの ID。TAINT_KEY=TAINT_VALUE
: スケジュールするTAINT_EFFECT
に関連付けられた Key-Value ペア。例:workloadType=untrusted
TAINT_EFFECT
: 次のいずれかの効果値。NoSchedule
: この taint を容認しない Pod はノード上にスケジュールされません。既存の Pod はノードから強制排除されません。PreferNoSchedule
: Kubernetes は、この taint を容認しない Pod をノード上にスケジュールすることを避けます。NoExecute
: ノードですでに実行されている Pod は、ノードから強制排除されます。ノードでまだ実行されていない Pod は、ノード上にスケジュールされません。
KUBERNETES_CLUSTER_KUBECONFIG
: Kubernetes クラスタの kubeconfig パス。
ノードプール内の各ノードに、コンテナ ワークロードで定義するセレクタに対応するラベルを適用します。
kubectl label NODE_ID \ LABEL_KEY:LABEL_VALUE \ --kubeconfig KUBERNETES_CLUSTER_KUBECONFIG
次の変数を置き換えます。
NODE_ID
: 専用ノードプール内のワーカーノードの ID。LABEL_KEY:LABEL_VALUE
: ノードラベルの Key-Value ペア。ワークロード マニフェストで指定したセレクタに対応しています。KUBERNETES_CLUSTER_KUBECONFIG
: Kubernetes クラスタの kubeconfig パス。
toleration とノード アフィニティ ルールを追加する
専用ノードプールに taint を追加しても、追加した taint に対応する toleration がなければ、ワークロードはそのノードプールでスケジュールできません。toleration をワークロードの仕様に追加して、taint が追加されたノードプールで Pod がスケジュールされるようにします。
専用ノードプールにラベルを付けた場合は、ノード アフィニティ ルールを追加して、そのノードプールにのみワークロードをスケジュールするように GDC に指示することもできます。
専用ノードプールで実行するようにコンテナ ワークロードを構成する手順は次のとおりです。
コンテナ ワークロードの
.spec.template.spec
セクションに次のセクションを追加します。kind: Deployment apiVersion: apps/v1 ... spec: ... template: spec: tolerations: - key: TAINT_KEY operator: Equal value: TAINT_VALUE effect: TAINT_EFFECT affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: LABEL_KEY operator: In values: - "LABEL_VALUE" ...
次のように置き換えます。
TAINT_KEY
: 専用ノードプールに適用した taint キー。TAINT_VALUE
: 専用ノードプールに適用した taint 値。TAINT_EFFECT
: 次のいずれかの効果値。NoSchedule
: この taint を容認しない Pod はノード上にスケジュールされません。既存の Pod はノードから強制排除されません。PreferNoSchedule
: Kubernetes は、この taint を容認しない Pod をノード上にスケジュールすることを避けます。NoExecute
: ノードですでに実行されている Pod は、ノードから強制排除されます。ノードでまだ実行されていない Pod は、ノード上にスケジュールされません。
LABEL_KEY
: 専用ノードプールに適用したノードラベルのキー。LABEL_VALUE
: 専用ノードプールに適用したノードラベル値。
たとえば、次の
Deployment
リソースは、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: workloadType operator: Equal value: untrusted effect: NoExecute affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: workloadType operator: In values: - "untrusted" containers: - name: my-app image: harbor-1.org-1.zone1.google.gdc.test/harborproject/my-app ports: - containerPort: 80 imagePullSecrets: - name: SECRET
デプロイを更新します。
kubectl apply -f deployment.yaml -n NAMESPACE \ --kubeconfig KUBERNETES_CLUSTER_KUBECONFIG
次の変数を置き換えます。
NAMESPACE
: コンテナ ワークロードのプロジェクト Namespace。KUBERNETES_CLUSTER_KUBECONFIG
: Kubernetes クラスタの kubeconfig パス。
GDC は影響を受ける Pod を再作成します。ノード アフィニティ ルールにより、作成した専用ノードプールに Pod が強制移動されます。この toleration によって、それらの Pod のみをノードに配置できます。
分離が機能していることを確認する
スケジューリングが正しく機能することを確認するには、次のコマンドを実行してワークロードが専用ノードプールにあるかどうかを確認します。
kubectl get pods -o=wide -n NAMESPACE \
--kubeconfig KUBERNETES_CLUSTER_KUBECONFIG
推奨事項とベスト プラクティス
ノード分離を設定したら、次の作業を行うことをおすすめします。
- 新しいノードプールを作成する場合、独自の taint をこれらの新しいノードプールに追加して、ほとんどの GDC マネージド ワークロードがこれらのノードで実行されないようにします。
- サードパーティ ツールをインストールする場合など、クラスタに新しいワークロードをデプロイする際は、常に Pod に必要な権限を監査してください。可能であれば、昇格権限を使用するワークロードを共有ノードにデプロイすることは避けてください。