使用 GKE Sandbox 隔离工作负载

您可以使用 GKE Sandbox 保护 Google Kubernetes Engine (GKE) 节点的宿主内核,使其免受运行不受信任或未知代码的容器的侵害。本文档向安全专家展示了如何启用 GKE Sandbox、在沙盒中运行 Pod 以及验证隔离。

您应当已熟悉 GKE Sandbox。

可用的沙盒类型

GKE Sandbox 支持以下沙盒类型,每种类型都使用特定技术将应用代码与主机内核分离:

  • gvisor:Linux 内核 API 的用户空间重新实现,不需要超出规定的特权。用户空间内核会代表主机内核拦截并处理大多数系统调用,从而限制对主机内核的直接访问。
  • microvm:使用嵌套虚拟化嵌套在宿主机虚拟机上的轻量级虚拟机。节点上的每个 Pod 都在其自己的嵌套虚拟机中运行,并具有自己的客机内核。由于代码在专用虚拟机中运行,因此这种沙盒类型提供的隔离性比 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 可能不支持运行本文档中的命令。
  • 如需按照为自动创建的节点选择沙盒类型部分中的步骤操作,请使用现有的 Autopilot 或 Standard 集群。如需使用 microVM 沙盒,您的节点必须运行 GKE 1.37.0-gke.4713000 版或更高版本。

为自动创建的节点选择沙盒类型

您可以将 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
      

      微型虚拟机沙盒的 ComputeClass 通过使用 enableNestedVirtualization 字段启用嵌套虚拟化。对于 microVM 沙盒,此字段为必填字段。如需使用此字段,您的集群必须运行 1.37.0-gke.4713000 版或更高版本。

    这些清单示例使用 nodePoolAutoCreation 字段来启用节点池自动创建。您还可以在使用 autopilot 字段的 ComputeClass 中指定沙盒配置,以在 Autopilot 模式下运行 Pod。如果您使用 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,您必须配置至少一个额外的节点池。需要额外的节点池,因为 GKE 需要集群中至少有一个节点池不使用 GKE Sandbox 来运行 GKE 管理的系统工作负载。如果您使用 gcloud CLI 创建集群,则必须先创建集群,然后再创建使用 GKE Sandbox 的节点池。
  • 如需选择微型虚拟机沙盒类型,您必须使用 gcloud CLI 或 GKE API。Google Cloud 控制台不支持选择微型虚拟机沙盒类型。

启用 gVisor 沙盒类型

如需在创建新节点池时手动启用 gVisor 沙盒,请选择以下选项之一:

控制台

  1. 在 Google Cloud 控制台中,前往 Kubernetes 集群页面。

    转到 Kubernetes 集群

  2. 点击要修改的集群的名称。系统会打开集群详细信息页面。

  3. 点击节点标签页。

  4. 在节点池部分中,点击 添加由用户管理的节点池。 添加节点池页面会打开。

  5. 在导航菜单中,点击节点并配置以下设置:

    1. 在映像类型下拉列表中,选择包含 Containerd 的 Container-Optimized OS (cos_containerd)。
    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 沙盒类型

您可以使用 gcloud CLI 或 GKE API 在创建节点池时启用 microVM 沙盒类型。 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 后,您无需使用沙盒,即可通过使用节点污点和容忍设置,在这些节点上运行受信任的应用。这些 Pod 称为“常规 Pod”,以将它们与沙盒化的 Pod 区分开来。

与沙盒化的 Pod 一样,常规 Pod 也无法访问其他Google Cloud 服务或集群元数据。此防护措施是节点配置的一部分。如果您的常规 Pod 或沙盒化的 Pod 需要访问Google Cloud 服务,请使用 Workload Identity Federation for GKE。

GKE Sandbox 会向可运行沙盒化 Pod 的节点添加以下标签和污点:

  • sandbox.gke.io/runtime: SANDBOX_TYPE 节点标签。
  • sandbox.gke.io/runtime=SANDBOX_TYPE:NoSchedule 个节点污点。只有具有匹配容忍设置的 Pod 才能调度到该节点上。

如果您使用 RuntimeClass 字段在沙盒中运行 Pod,则 GKE 会自动将节点亲和性和容忍设置应用于该 Pod。如需在启用了 GKE Sandbox 的节点上运行常规 Pod,您必须手动将以下选择器应用于 Pod 规范:

  • 如需让 Pod 在需要时在使用了 GKE Sandbox 的节点上运行,请仅添加针对节点污点的容忍设置。
  • 如需仅在使用 GKE Sandbox 的节点上运行 Pod,请添加节点选择器和节点污点的容忍设置。

以下步骤展示了如何在采用 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 清单中节点亲和性和容忍设置是否正确。

  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 可访问的内核版本不同,因为 Pod 只能看到 gVisor 的用户空间内核或微虚拟机的 guest 内核。

  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,请删除节点池。

后续步骤