GKE Sandbox を使用してワークロードを分離する

GKE Sandbox を使用すると、信頼できないコードや不明なコードを実行するコンテナから Google Kubernetes Engine(GKE)ノードのホストカーネルを保護できます。このドキュメントでは、セキュリティ スペシャリストが GKE Sandbox を有効にして、サンドボックスで Pod を実行し、分離を確認する方法について説明します。

GKE Sandbox に精通している必要があります。

使用可能なサンドボックス タイプ

GKE Sandbox は、次のサンドボックス タイプをサポートしています。各タイプは、特定のテクノロジーを使用してアプリケーション コードをホストカーネルから分離します。

  • gvisor: 権限昇格を必要としない Linux カーネル API のユーザー空間を再実装したものです。ユーザー空間カーネルは、ホストカーネルに代わってシステム コールの大部分をインターセプトして処理するため、ホストカーネルへの直接アクセスが制限されます。
  • microvm: ネストされた仮想化を使用してホスト VM にネストされた軽量 VM。ノード上の各 Pod は、独自のゲストカーネルを持つ独自のネストされた VM で実行されます。コードは専用の VM で実行されるため、このサンドボックス タイプは gVisor サンドボックスよりも強力な分離を提供します。

各サンドボックス タイプの仕組みと、特定のタイプを使用するタイミングについては、GKE Sandbox についてをご覧ください。

制限事項

GKE Sandbox と特定のサンドボックス テクノロジーには、GPU と TPU のサポートや特定の Linux 機能と Kubernetes 機能のサポートなど、さまざまな制限があります。詳細については、制限事項をご覧ください。

始める前に

作業を始める前に、次のタスクが完了していることを確認してください。

  • Google Kubernetes Engine API を有効にする。
  • Google Kubernetes Engine API を有効化
  • このタスクに Google Cloud CLI を使用する場合は、gcloud CLI をインストールして初期化します。gcloud CLI をインストール済みの場合は、gcloud components update コマンドを実行して最新のバージョンを取得します。以前のバージョンの gcloud CLI では、このドキュメントのコマンドを実行できない場合があります。

自動作成されたノードのサンドボックス タイプを選択する

ComputeClasses を Autopilot モードまたはノードプールの自動作成で使用すると、GKE が作成するノードで GKE Sandbox を有効にできます。Autopilot クラスタでは、gVisor がデフォルトでサポートされているため、ComputeClass からサンドボックス構成を省略できます。

自動作成されたノード用に GKE Sandbox を構成する手順は次のとおりです。

  1. 既存の Autopilot クラスタまたは Standard クラスタに接続します。

    gcloud container clusters get-credentials CLUSTER_NAME \
        --location=CONTROL_PLANE_LOCATION
    

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

    • CLUSTER_NAME: クラスタの名前。
    • CONTROL_PLANE_LOCATION: クラスタのコントロール プレーンのリージョンまたはゾーン。
  2. 必要なサンドボックス テクノロジーに応じて、次のいずれかの ComputeClass マニフェストを保存します。

    • gVisor:

      apiVersion: cloud.google.com/v1
      kind: ComputeClass
      metadata:
        name: sandbox-gvisor-class
      spec:
        priorities:
        - machineFamily: n4
        - machineFamily: c4
        nodePoolConfig:
          sandbox:
            type: gvisor
        nodePoolAutoCreation:
          enabled: true
        whenUnsatisfiable: DoNotScaleUp
      
    • microVM:

      apiVersion: cloud.google.com/v1
      kind: ComputeClass
      metadata:
        name: sandbox-microvm-class
      spec:
        priorities:
        - machineFamily: n4
        - machineFamily: c4
        nodePoolConfig:
          sandbox:
            type: microvm
        priorityDefaults:
          enableNestedVirtualization: true
        nodePoolAutoCreation:
          enabled: true
        whenUnsatisfiable: DoNotScaleUp
      

      microVM サンドボックスの ComputeClass では、enableNestedVirtualization フィールドを使用してネストされた仮想化を有効にします。このフィールドは microVM サンドボックスで必須です。このフィールドを使用するには、クラスタでバージョン 1.37.0-gke.4713000 以降を実行する必要があります。

    これらのマニフェストの例では、nodePoolAutoCreation フィールドを使用してノードプールの自動作成を有効にしています。autopilot フィールドを使用して Autopilot モードで Pod を実行する ComputeClass でサンドボックス構成を指定することもできます。Autopilot クラスタを使用する場合、GKE は nodePoolAutoCreation フィールドと autopilot フィールドの両方を無視します。

  3. ComputeClass を作成します。

    kubectl apply -f PATH_TO_COMPUTE_CLASS_MANIFEST
    

    PATH_TO_COMPUTE_CLASS_MANIFEST は、ComputeClass マニフェストのパスに置き換えます。

この ComputeClass を選択してサンドボックス環境をリクエストするには、Pod のサンドボックス環境をリクエストするをご覧ください。

ノードプールの作成時にサンドボックス タイプを選択する

Standard クラスタで新しいノードプールを作成するときに、GKE Sandbox を手動で有効にできます。GKE Sandbox を手動で有効にする場合は、次の制限が適用されます。

  • Standard クラスタの作成時に GKE Sandbox を有効にするには、少なくとも 1 つの追加ノードプールを構成する必要があります。GKE では、GKE マネージド システム ワークロードを実行するために、GKE Sandbox を使用しないノードプールがクラスタに少なくとも 1 つ必要であるため、追加のノードプールが必要です。gcloud CLI を使用してクラスタを作成する場合は、クラスタを作成してから、GKE Sandbox を使用するノードプールを作成する必要があります。
  • microVM サンドボックス タイプを選択するには、gcloud CLI または GKE API を使用する必要があります。Google Cloud コンソールでは、microVM サンドボックス タイプを選択できません。

gVisor サンドボックス タイプを有効にする

新しいノードプールを作成するときに gVisor サンドボックスを手動で有効にするには、次のいずれかのオプションを選択します。

コンソール

  1. Google Cloud コンソールで [Kubernetes クラスタ] ページに移動します。

    Kubernetes クラスタに移動

  2. 変更するクラスタの名前をクリックします。[クラスタの詳細] ページが開きます。

  3. [ノード] タブをクリックします。

  4. [ノードプール] セクションで、 [ユーザー管理のノードプールを追加] をクリックします。[ノードプールの追加] ページが開きます。

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

    1. [イメージの種類] プルダウン リストで、[containerd(cos_containerd)が含まれている Container-Optimized OS] を選択します。
    2. [マシンの構成] セクションで、ノードのマシンシリーズとマシンタイプを選択します。
    3. 省略可: サポートされている GPU タイプまたはサポートされている TPU タイプを選択します。
  6. ナビゲーション メニューで [セキュリティ] をクリックします。[ノードのセキュリティ] ページが開きます。

  7. [gVisor でサンドボックスを有効にする] チェックボックスをオンにします。

  8. ノードプールを作成するには、[作成] をクリックします。

gcloud

サンドボックスに gVisor を使用するノードプールを作成するには、次のコマンドを実行します。

gcloud container node-pools create NODE_POOL_NAME \
    --cluster=CLUSTER_NAME \
    --location=CONTROL_PLANE_LOCATION \
    --sandbox=type=gvisor

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

  • NODE_POOL_NAME: ノードプールの名前。
  • CLUSTER_NAME: クラスタの名前。
  • CONTROL_PLANE_LOCATION: クラスタのコントロール プレーンのリージョンまたはゾーン。

サポートされている GPU タイプまたはサポートされている TPU タイプを使用するノードプールを作成するときに、gVisor サンドボックスを有効にすることもできます。詳細については、次のドキュメントをご覧ください。

microVM サンドボックス タイプを有効にする

microVM サンドボックス タイプは、gcloud CLI または GKE API を使用してノードプールを作成するときに有効にできます。 Google Cloud コンソールでは、microVM サンドボックス タイプの有効化はサポートされていません。microVM サンドボックスを使用するノードプールを作成するには、次のコマンドを実行します。

gcloud container node-pools create NODE_POOL_NAME \
    --cluster=CLUSTER_NAME \
    --location=CONTROL_PLANE_LOCATION \
    --sandbox=type=microvm \
    --enable-nested-virtualization \
    --machine-type=MACHINE_TYPE

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

  • NODE_POOL_NAME: ノードプールの名前。
  • CLUSTER_NAME: クラスタの名前。
  • CONTROL_PLANE_LOCATION: クラスタのコントロール プレーンのリージョンまたはゾーン。
  • MACHINE_TYPE: ノードのマシンタイプ。この値は、ネストされた仮想化をサポートするマシンタイプにする必要があります。詳細については、マシンシリーズの比較表の「ネストされた仮想化」行をご覧ください。

モニタリングとロギングの有効化

サンドボックスからログと指標を収集して表示するには、クラスタで次のオブザーバビリティ サービスが有効になっていることを確認します。

これらのサービスは、新しいすべての GKE クラスタでデフォルトで有効になっています。

Pod のサンドボックス環境をリクエストする

サンドボックスで特定の Pod を実行するには、Pod 仕様で gvisor または microvm RuntimeClass を指定します。GKE は、指定されたサンドボックス タイプを使用するノードで Pod をスケジュールします。Pod 仕様でサンドボックス タイプを選択する手順は次のとおりです。

  1. ComputeClass を使用して GKE Sandbox を有効にするか、手動で作成したノードプールを使用するかに応じて、次のいずれかの Deployment マニフェストの例を保存します。

    • ComputeClasses:

      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: sandbox-pod
        labels:
          environment: sandbox
      spec:
        replicas: 2
        selector:
          matchLabels:
            environment: sandbox
        template:
          metadata:
            labels:
              environment: sandbox
          spec:
            nodeSelector:
              cloud.google.com/compute-class: COMPUTECLASS_NAME
            runtimeClassName: SANDBOX_TYPE
            
            containers:
            - name: nginx
              image: nginx
      

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

      • COMPUTECLASS_NAME: 自動作成されたノードのサンドボックス タイプを選択するで説明されているように、作成した ComputeClass の名前。

      • SANDBOX_TYPE: Pod に使用するサンドボックス タイプ。次の値を使用できます。

        • gvisor
        • microvm

        指定するサンドボックス タイプは、選択した ComputeClass で有効になっているサンドボックス タイプと一致する必要があります。

    • 手動で作成したノードプール:

      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: SANDBOX_TYPE
            containers:
            - name: httpd
              image: httpd
      

      SANDBOX_TYPE は、サンドボックス タイプに置き換えます。次の値を使用できます。

      • gvisor
      • microvm

      指定するサンドボックス タイプは、クラスタ内の既存のノードプールのサンドボックス タイプと一致する必要があります。

  2. Deployment を作成します。

    kubectl apply -f PATH_TO_DEPLOYMENT_MANIFEST
    

    PATH_TO_DEPLOYMENT_MANIFEST は、Deployment マニフェストのパスに置き換えます。

  3. Pod が作成されたことを確認します。

    kubectl get pods
    

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

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

runtimeClassName フィールドを使用して、サポートされている GPU タイプまたはサポートされている TPU タイプで Pod を実行するときに、サンドボックスをリクエストすることもできます。詳細については、次のドキュメントをご覧ください。

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

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

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

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

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

  • sandbox.gke.io/runtime: SANDBOX_TYPE ノードラベル。
  • sandbox.gke.io/runtime=SANDBOX_TYPE:NoSchedule ノード taint。一致する toleration を持つ Pod のみ、ノードにスケジュールできます。

RuntimeClass フィールドを使用してサンドボックスで Pod を実行すると、GKE は自動的にノード アフィニティと toleration を Pod に適用します。GKE Sandbox を使用するノードで通常の Pod を実行するには、次のセレクタを Pod 仕様に手動で適用する必要があります。

  • 必要に応じて GKE Sandbox を使用するノードで Pod を実行できるようにするには、ノード taint の toleration のみを追加します。
  • GKE Sandbox を使用するノードでのみ Pod を実行するには、ノードセレクタとノード taint の toleration を追加します。

次の手順では、GKE Sandbox を使用するノードで通常の Pod を実行する方法について説明します。

  1. 次の Deployment マニフェストを httpd-regular.yaml として保存します。

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

    SANDBOX_TYPE は、gvisor や microvm などのサンドボックス タイプに置き換えます。

  2. Deployment を作成します。

    kubectl apply -f httpd-regular.yaml
    

    Pod のスケジュールを設定できない場合は、Pod のマニフェストでノード アフィニティと toleration が正しく設定されていることを確認します。

  3. Pod がサンドボックスにないことを確認します。

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

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

    httpd-db5899bc9-dk7lk: SANDBOX_TYPE
    httpd-regular-5bf87996c6-cfmmd:
    

    httpd-regular Pod には RuntimeClass 値がありません。これは、Pod がサンドボックスにないことを意味します。

  4. 通常の Pod が GKE Sandbox を使用するノードで実行されていることを確認します。

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

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

    httpd-db5899bc9-dk7lk: gke-cluster-2-pool-1-75c8fc63-h373
    httpd-regular-5bf87996c6-cfmmd: gke-cluster-2-pool-1-75c8fc63-h373
    

    サンドボックス Pod と通常の Pod の両方が同じノードに存在します。これは、通常の Pod が GKE Sandbox を使用するノードで実行されていることを示しています。

サンドボックスの構成を確認する

以降のセクションでは、Pod がサンドボックスで実行されていることと、サンドボックス化された Pod がホスト カーネルから分離されていることを確認する方法について説明します。これらのセクションでは、Pod のサンドボックス環境をリクエストするで作成した Deployment の例を使用します。

Pod がサンドボックスで実行されていることを確認する

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

  • 実行中の各 Pod の RuntimeClass を取得します。

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

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

    httpd-db5899bc9-dk7lk: gvisor
    httpd-db5899bc9-ab3cd: gvisor
    

    出力に gvisor または microvm が表示されている場合、Pod はサンドボックスで実行されています。

サンドボックス化された Pod がホストから分離されていることを確認する

サンドボックス化された Pod がホストノードから分離されているかどうかを確認するには、利用可能な仮想デバイスと、Pod がアクセスできるカーネルのバージョンを確認します。

  1. gVisor サンドボックスと microVM サンドボックスの場合は、Pod がアクセスできるカーネルのバージョンがホストノードのカーネル バージョンと異なるかどうかを確認します。

    1. Pod がアクセスできるカーネルのバージョンを取得します。

      kubectl exec POD_NAME -- uname -r
      

      POD_NAME は、Pod の名前で置き換えます。

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

      4.19.0-gvisor
      
    2. ホストノードのカーネルのバージョンを取得します。

      kubectl get node NODE_NAME \
          -o jsonpath='{.status.nodeInfo.kernelVersion}'
      

      NODE_NAME は、Pod を実行するノードの名前に置き換えます。

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

      6.12.94+
      

    Pod は gVisor のユーザー空間カーネルまたは microVM のゲスト カーネルのみを認識するため、ホストノードのカーネル バージョンは、サンドボックス化された Pod がアクセスできるカーネル バージョンとは異なります。

  2. microVM サンドボックスの場合、Pod がアクセスできるデバイスが Cloud Hypervisor によって仮想化されているかどうかを確認することもできます。

    kubectl exec POD_NAME -- cat /sys/class/dmi/id/product_name
    

    出力が cloud-hypervisor の場合、Pod は microVM サンドボックスにあります。

GKE Sandbox を無効にする

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

次のステップ