GKE Sandbox によるワークロード分離の強化


このページでは、Pod 内のコンテナが不明なコードや信頼できないコードを実行したとき、またはそのノードから特別に切り離す必要があるときに、GKE Sandbox を使用してノードのホストカーネルを保護する方法について説明します。

GKE Sandbox の可用性

GKE Sandbox は、GKE バージョン 1.27.4-gke.800 以降を実行する Autopilot クラスタで使用できます。サンドボックスで Autopilot ワークロードのデプロイを開始するには、GKE Sandbox を使用するに進みます。

新規または既存の GKE Standard クラスタで GKE Sandbox を使用するには、クラスタで GKE Sandbox を手動で有効にする必要があります。

始める前に

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

  • Google Kubernetes Engine API を有効にします。
  • Google Kubernetes Engine API の有効化
  • このタスクに Google Cloud CLI を使用する場合は、gcloud CLI をインストールして初期化します。すでに gcloud CLI をインストールしている場合は、gcloud components update を実行して最新のバージョンを取得します。

新しい Standard クラスタで GKE Sandbox を有効にする

新しいクラスタの作成時に作成されるデフォルトのノードプールでは、それがクラスタ内の唯一のノードプールである場合、GKE Sandbox を使用できません。これは、GKE マネージド システムのワークロードは、信頼できないサンドボックス化されたワークロードとは別に実行する必要があるためです。クラスタの作成時に GKE Sandbox を有効にするには、クラスタに少なくとも 1 つのノードプールを追加する必要があります。

コンソール

クラスタを表示するには、Google Cloud コンソールで Google Kubernetes Engine のメニューに移動します。

  1. Google Cloud コンソールで Google Kubernetes Engine のページに移動します。

    Google Kubernetes Engine に移動

  2. [ 作成] をクリックします。

  3. 省略可能、ただし推奨: ナビゲーション メニューの [クラスタ] で [機能] をクリックし、次のチェックボックスをオンにします。これにより、gVisor がメッセージがロギングされます。

    • Cloud Logging
    • Cloud Monitoring
    • Managed Service for Prometheus
  4. [ ノードプールを追加] をクリックします。

  5. ナビゲーション メニューの [ノードプール] で新しいノードプールを開き、[ノード] をクリックします。

  6. ノードプールに次の設定を構成します。

    1. [イメージの種類] プルダウン リストから、[containerd(cos_containerd)が含まれている Container-Optimized OS] を選択します。 これは、GKE Sandbox でサポートされている唯一のイメージタイプです。
    2. [マシンの構成] で [シリーズ] と [マシンタイプ] を選択します。

  7. ナビゲーション メニューで、構成するノードプールの名前の下にある [セキュリティ] をクリックし、[gVisor でサンドボックスを有効にする] チェックボックスをオンにします。

  8. クラスタとノードプールを必要に応じて構成します。

  9. [作成] をクリックします。

gcloud

デフォルトのノードプールで GKE Sandbox を有効にすることはできません。また、新しいクラスタを作成するときに、gcloud コマンドを実行します。代わりに、通常どおりにクラスタを作成します。必須ではありませんが、Logging と Monitoring を有効にして、gVisor メッセージをロギングすることをおすすめします。

次に、-- sandbox フラグを type=gvisor に設定して、gcloud container node-pools create コマンドを実行します。GKE Sandbox では、ノードイメージ タイプを cos_containerd にする必要があります。

gcloud container node-pools create NODE_POOL_NAME \
  --cluster=CLUSTER_NAME \
  --node-version=NODE_VERSION \
  --machine-type=MACHINE_TYPE \
  --image-type=cos_containerd \
  --sandbox type=gvisor

次の変数を置き換えます。

  • NODE_POOL_NAME: 新しいノードプールの名前。
  • CLUSTER_NAME: クラスタの名前。
  • NODE_VERSION: ノードプールに使用するバージョン。
  • MACHINE_TYPE: ノードに使用するマシンのタイプ。GKE Sandbox は e2-microe2-smalle2-medium マシンタイプをサポートしていません。

既存の Standard クラスタで GKE Sandbox を有効にする

既存の Standard クラスタで GKE Sandbox を有効にするには、新しいノードプールを追加し、そのノードプールのこの機能を有効にします。

コンソール

GKE Sandbox を有効にして新しいノードプールを作成するには:

  1. Google Cloud コンソールで Google Kubernetes Engine のページに移動します。

    Google Kubernetes Engine に移動

  2. 変更するクラスタの名前をクリックします。

  3. [ ノードプールを追加] をクリックします。

  4. 必要に応じて [ノードプールの詳細] ページを構成します。

  5. ナビゲーション メニューで [ノード] をクリックし、次の設定を構成します。

    1. [イメージの種類] プルダウン リストから、[containerd(cos_containerd)が含まれている Container-Optimized OS] を選択します。これは、GKE Sandbox でサポートされている唯一のイメージタイプです。
    2. [マシンの構成] で [シリーズ] と [マシンタイプ] を選択します。

  6. ナビゲーション メニューで [セキュリティ] をクリックし、[gVisor でサンドボックスを有効にする] チェックボックスをオンにします。

  7. [作成] をクリックします。

gcloud

GKE Sandbox を有効にする新しいノードプールを作成するには、次のようなコマンドを使用します。

gcloud container node-pools create NODE_POOL_NAME \
  --cluster=CLUSTER_NAME \
  --machine-type=MACHINE_TYPE \
  --image-type=cos_containerd \
  --sandbox type=gvisor

GKE Sandbox では、ノードイメージ タイプを cos_containerd にする必要があります。

省略可: モニタリングとロギングを有効にする

クラスタで Cloud Logging と Cloud Monitoring を有効にして、gVisor メッセージをログに記録します。この操作は省略可能ですが、行うことをおすすめします。これらのサービスは、新しいクラスタではデフォルトで有効になります。

Google Cloud コンソールを使用して、既存のクラスタでこれらの機能を有効にできます。

  1. Google Cloud コンソールで Google Kubernetes Engine のページに移動します。

    Google Kubernetes Engine に移動

  2. 変更するクラスタの名前をクリックします。

  3. [機能] の [Cloud Logging] フィールドで、[ Cloud Logging の編集] をクリックします。

  4. [Cloud Logging を有効にする] チェックボックスをオンにします。

  5. [変更を保存] をクリックします。

  6. [Cloud Monitoring] フィールドと [Managed Service for Prometheus] フィールドで同じ手順を繰り返し、これらの機能を有効にします。

Autopilot と Standard で GKE Sandbox を使用する

GKE Sandbox が有効になっている Autopilot クラスタと Standard クラスタでは、Pod 仕様で gvisor RuntimeClass を指定して Pod のサンドボックス環境をリクエストします。

Autopilot クラスタでは、GKE バージョン 1.26.0-gke.2500 以降を実行していることを確認します。

サンドボックスでのアプリケーションの実行

GKE Sandbox が有効になっているノードで Deployment を実行するには、次の例のように spec.template.spec.runtimeClassNamegvisor に設定します。

# httpd.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpd
  labels:
    app: httpd
spec:
  replicas: 1
  selector:
    matchLabels:
      app: httpd
  template:
    metadata:
      labels:
        app: httpd
    spec:
      runtimeClassName: gvisor
      containers:
      - name: httpd
        image: httpd

Deployment を作成します。

kubectl apply -f httpd.yaml

GKE Sandbox が有効になっているノードに Pod がデプロイされます。デプロイを確認するには、Pod がデプロイされているノードを探します。

kubectl get pods

出力は次のようになります。

NAME                    READY   STATUS    RESTARTS   AGE
httpd-db5899bc9-dk7lk   1/1     Running   0          24s

出力で Pod の名前を探してから、RuntimeClass の値を確認します。

kubectl get pods POD_NAME -o jsonpath='{.spec.runtimeClassName}'

出力は gvisor です。

または、各 Pod の RuntimeClass を一覧表示して、gvisor に設定されている Pod を探します。

kubectl get pods -o jsonpath=$'{range .items[*]}{.metadata.name}: {.spec.runtimeClassName}\n{end}'

次のような出力が表示されます。

POD_NAME: gvisor

Pod がサンドボックス内で実行されていることを確認する方法は、サンドボックス内のデータに依存しないため、信頼性が高い方法となります。サンドボックス内から報告されたものは信頼できません。問題が存在していることや、悪意のある可能性があります。

通常の Pod とサンドボックス Pod の実行

このセクションの手順は、Standard モードのワークロードに適用されます。Autopilot モードでは、通常の Pod をサンドボックス Pod と並行して実行する必要はありません。これは、Autopilot 料金モデルによって、ノードでスケジュールされる Pod の数を手動で最適化する必要がないためです。

ノードプールで GKE Sandbox を有効にした後、Node Taints と許容値でサンドボックスを使用するのではなく、信頼できるアプリケーションをノードで実行できます。 これらの Pod は、「通常の Pod」といわれ、サンドボックスの Pod と区別されます。

通常の Pod は、サンドボックス化された Pod と同様に、他の Google Cloud サービスやクラスタ メタデータにアクセスできません。この設定は、ノードの構成時に有効になります。通常の Pod またはサンドボックス化された Pod が Google Cloud サービスにアクセスする必要がある場合は、GKE 用 Workload Identity 連携を使用します。

GKE Sandbox は、サンドボックス化されたポッドを実行できるノードに次のラベルと taint を追加します。

labels:
  sandbox.gke.io/runtime: gvisor
taints:
- effect: NoSchedule
  key: sandbox.gke.io/runtime
  value: gvisor

GKE Sandbox は、Pod マニフェストのノード アフィニティと toleration に加えて、次のノード アフィニティと許容値をすべての Pod に適用し、RuntimeClassgvisor に設定します。

affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
      - matchExpressions:
        - key: sandbox.gke.io/runtime
          operator: In
          values:
          - gvisor
tolerations:
  - effect: NoSchedule
    key: sandbox.gke.io/runtime
    operator: Equal
    value: gvisor

GKE Sandbox が有効なノードで通常の Pod のスケジュールを設定するには、上記のノード アフィニティと toleration を Pod マニフェストに手動で適用します。

  • GKE Sandbox が有効なノードで Pod が実行可能な場合は、toleration を追加します。
  • GKE Sandbox が有効なノードで Pod を実行する必要がある場合は、上記のノード アフィニティと toleration の両方を追加します。

たとえば、次のマニフェストでは、サンドボックスでのアプリケーションの実行で使用したマニフェストを変更します。runtimeClass を削除して上記の taint と toleration の両方を追加し、サンドボックス化した Pod を含むノードで通常の Pod として実行します。

# httpd-no-sandbox.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpd-no-sandbox
  labels:
    app: httpd
spec:
  replicas: 1
  selector:
    matchLabels:
      app: httpd
  template:
    metadata:
      labels:
        app: httpd
    spec:
      containers:
      - name: httpd
        image: httpd
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: sandbox.gke.io/runtime
                operator: In
                values:
                - gvisor
      tolerations:
        - effect: NoSchedule
          key: sandbox.gke.io/runtime
          operator: Equal
          value: gvisor

まず、サンドボックスで Deployment が実行されていないことを確認します。

kubectl get pods -o jsonpath=$'{range .items[*]}{.metadata.name}: {.spec.runtimeClassName}\n{end}'

出力は次のようになります。

httpd-db5899bc9-dk7lk: gvisor
httpd-no-sandbox-5bf87996c6-cfmmd:

前に作成した httpd Deployment はサンドボックス内で実行されます。これは、runtimeClass が gvisor のためです。httpd-no-sandbox Deployment の runtimeClass には値が設定されていないため、サンドボックスでは実行されません。

次に、GKE Sandbox を使用するノードで、サンドボックス化されていない Deployment が実行されていることを確認します。

kubectl get pod -o jsonpath=$'{range .items[*]}{.metadata.name}: {.spec.nodeName}\n{end}'

ノードプールの名前は、nodeName の値に埋め込まれます。GKE Sandbox が有効なノードプール内のノードで、Pod が実行されていることを確認します。

メタデータの保護の確認

サンドボックス ポッドを実行できるノードからメタデータが保護されていることを確認するには、次のようにテストを行います。

  1. kubectl apply -f を使用して、次のマニフェストから、サンドボックス化された Deployment を作成します。curlコマンドを含む fedora イメージを使用します。ポッドは /bin/sleep コマンドを実行して、Deployment が 10,000 秒間実行されるようにします。

    # sandbox-metadata-test.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: fedora
      labels:
        app: fedora
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: fedora
      template:
        metadata:
          labels:
            app: fedora
        spec:
          runtimeClassName: gvisor
          containers:
          - name: fedora
            image: fedora
            command: ["/bin/sleep","10000"]
    
  2. kubectl get pods を使用して Pod の名前を取得し、kubectl exec を使用して、Pod にインタラクティブに接続します。

    kubectl exec -it POD_NAME /bin/sh
    

    /bin/sh セッションで、ポッド内のコンテナに接続されます。

  3. インタラクティブ セッションで、クラスタ メタデータを返す URL にアクセスします。

    curl -s "http://169.254.169.254/computeMetadata/v1/instance/attributes/kube-env" -H "Metadata-Flavor: Google"
    

    パケットがサイレントで破棄されるため、コマンドが停止し、最終的にタイムアウトになります。

  4. Ctrl + C を押して curl コマンドを終了し、exit を入力して Pod から切断します。

  5. YAML マニフェストから RuntimeClass を削除し、kubectl apply -f FILENAME を使用して Pod を再デプロイします。サンドボックス化された Pod が終了し、GKE Sandbox のないノードで再作成されます。

  6. 新しい Pod 名を取得し、kubectl exec を使用して Pod に接続します。curl コマンドを再度実行します。今回は、結果が返されます。この出力例は省略されています。

    ALLOCATE_NODE_CIDRS: "true"
    API_SERVER_TEST_LOG_LEVEL: --v=3
    AUTOSCALER_ENV_VARS: kube_reserved=cpu=60m,memory=960Mi,ephemeral-storage=41Gi;...
    ...
    

    exit と入力して、Pod から切断します。

  7. デプロイを削除します。

    kubectl delete deployment fedora
    

GKE Sandbox を無効にする

GKE Autopilot クラスタまたは GKE Standard ノードプールでは GKE Sandbox を無効にできません。GKE Sandbox の使用を停止する場合は、ノードプールを削除します。

次のステップ