验证 GKE 控制平面虚拟机完整性


本指南介绍了如何验证 Google Kubernetes Engine (GKE) 用于控制平面虚拟机的 Compute Engine 虚拟机 (VM) 映像的完整性。本指南面向监控控制平面日志并希望验证以下内容的安全团队:

  • 控制平面虚拟机使用通过安全启动和完整性监控进行加密验证的正版固件和其他启动软件启动。
  • 控制平面虚拟机从真实的 GKE OS 映像启动。

您还可以对工作节点的操作系统映像和启动完整性执行此验证。

本页介绍了 GKE 中一组可选控制平面功能的一部分,可让您执行各种任务,例如验证控制平面安全状况,或使用您管理的密钥在控制平面中配置加密和凭据签名。 如需了解详情,请参阅 GKE 控制平面授权简介

默认情况下, Google Cloud 会对托管式控制平面应用各种安全措施。 本页介绍了一些可选功能,可让您更好地了解 GKE 控制平面或对其进行控制。

虚拟机完整性验证简介

默认情况下,所有 GKE 控制平面实例都是安全强化型虚拟机,这类虚拟机经过强化,可使用安全启动、测量启动、虚拟可信平台模块 (vTPM) 和 UEFI 固件等安全功能。所有 GKE 节点还启用了完整性监控,该功能会根据基准“良好”启动顺序验证每个安全强化型虚拟机的启动顺序。此验证会针对每个启动顺序阶段返回通过或失败结果,并将这些结果添加到 Cloud Logging。完整性监控在所有 GKE 集群中默认处于启用状态,并会验证以下阶段:

  • 早期启动序列:从 UEFI 固件启动到引导加载程序接管控制的整个过程。已作为 earlyBootReportEvent 添加到虚拟机日志中。
  • 后期启动序列:从引导加载程序接管控制权到操作系统内核接管控制权。已添加到虚拟机日志中,标识为 lateBootReportEvent

GKE 还会向 Logging 添加控制平面虚拟机创建日志。这些日志包含用于标识机器的元数据,以及有关虚拟机映像和启动顺序的详细信息。Google Cloud 会在 GitHub 上的 gke-vsa 代码库中为每个 GKE 控制平面虚拟机映像发布验证摘要证明 (VSA)。VSA 使用 in-toto 框架进行认证。您可以根据相应的 VSA 验证集群的控制平面虚拟机日志,以验证控制平面节点是否按预期启动。

执行这些验证有助于您实现以下目标:

  • 确保控制平面上的软件受安全启动和完整性监控保护,与预期的源代码相匹配,并且与其他 Google Cloud 客户使用的映像完全相同。
  • 增强对 GKE 如何保护控制平面的信心。

价格

在 GKE 中,此功能无需额外付费。

准备工作

在开始之前,请确保您已执行以下任务:

  • 启用 Google Kubernetes Engine API。
  • 启用 Google Kubernetes Engine API
  • 如果您要使用 Google Cloud CLI 执行此任务,请安装初始化 gcloud CLI。 如果您之前安装了 gcloud CLI,请运行 gcloud components update 以获取最新版本。
  • Enable the Cloud Logging API.

    Enable the API

  • 确保您已拥有运行 1.29 或更高版本的 GKE Autopilot 模式或 Standard 模式集群。

所需的角色

如需获得验证控制平面虚拟机完整性所需的权限,请让您的管理员为您授予项目的以下 IAM 角色:

如需详细了解如何授予角色,请参阅管理对项目、文件夹和组织的访问权限

您也可以通过自定义角色或其他预定义角色来获取所需的权限。

检查启动顺序阶段是否失败

如果控制平面虚拟机失败或成功完成启动序列的某个阶段,完整性监控会向 Logging 添加日志。如需查看启动失败事件,请运行以下命令:

  1. 在 Google Cloud 控制台中,前往 Logs Explorer 页面:

    转到 Logs Explorer

  2. 查询字段中,指定以下查询:

    jsonPayload.@type="type.googleapis.com/cloud_integrity.IntegrityEvent"
    jsonPayload.earlyBootReportEvent.policyEvaluationPassed="false" OR jsonPayload.lateBootReportEvent.policyEvaluationPassed="false"
    jsonPayload.metadata.isKubernetesControlPlaneVM="true"
    

    您还可以在此查询中将 false 替换为 true,以检查是否有成功的启动事件。

  3. 点击运行查询。如果您没有看到结果,则说明您的控制平面虚拟机通过了所有完整性监控检查。如果您看到输出,请继续执行下一步来识别相应的集群。

  4. 在启动完整性日志失败中,复制 resource.labels.instance_id 字段中的值。

  5. 查询字段中,指定以下查询:

    protoPayload.@type="type.googleapis.com/google.cloud.audit.AuditLog"
    protoPayload.metadata.isKubernetesControlPlaneVM="true"
    resource.labels.instance_id="INSTANCE_ID"
    protoPayload.methodName="v1.compute.instances.insert"
    

    INSTANCE_ID 替换为上一步中的 instance_id 字段的值。

  6. 点击运行查询protoPayload.metadata.parentResource.parentResourceId 字段中的值是 GKE 集群 ID。

  7. 查找 GKE 集群的名称:

    gcloud asset query \
        --organization=ORGANIZATION_ID \
        --statement="SELECT name FROM container_googleapis_com_Cluster WHERE resource.data.id='CLUSTER_ID';"
    

    替换以下内容:

    • ORGANIZATION_ID:您的Google Cloud 组织的数字 ID。
    • CLUSTER_ID:上一步中的 protoPayload.metadata.parentResource.parentResourceId 字段的值。

    输出类似于以下内容:

    # lines omitted for clarity
    //container.googleapis.com/projects/PROJECT_ID/locations/LOCATION/clusters/CLUSTER_NAME
    

    此输出包含以下字段:

    • PROJECT_ID:您的 Google Cloud 项目 ID。
    • LOCATION:集群的位置。
    • CLUSTER_NAME:集群的名称。

查找和检查控制平面虚拟机日志

与 GKE 集群对应的 Compute Engine 虚拟机创建日志存储在 _Default 日志存储桶中。如需查找集群控制平面虚拟机的创建日志并检索此元数据,请执行以下操作:

  1. 在 Google Cloud 控制台中,前往 Logs Explorer 页面:

    转到 Logs Explorer

  2. 查询字段中,指定以下查询:

    resource.type="gce_instance"
    protoPayload.methodName="v1.compute.instances.insert"
    protoPayload.metadata.isKubernetesControlPlaneVM="true"
    
  3. 点击运行查询。如果您没有看到结果,请检查您是否满足准备工作部分中列出的所有要求。

  4. 在查询结果中,检查 metadata 字段。输出类似于以下内容:

    # fields omitted for clarity
    "metadata": {
      "usedResources": {
        "attachedDisks": [
          {
            "sourceImageId": "9046093115864736653",
            "sourceImage": "https://www.googleapis.com/compute/v1/projects/1234567890/global/images/gke-1302-gke1627000-cos-113-18244-85-49-c-pre",
            "isBootDisk": true
          }
    # fields omitted for clarity
    

    metadata 字段包含以下信息:

    • usedResources:用于创建虚拟机的资源列表。
    • attachedDisks:虚拟机的启动磁盘。
    • sourceImageId:虚拟机映像的唯一 ID。
    • sourceImage:来源虚拟机映像的网址。此字段中的值的语法为 https://www.googleapis.com/compute/v1/projects/PROJECT_NUMBER/global/images/IMAGE_NAME,其中 PROJECT_NUMBER 是托管控制平面虚拟机的Google Cloud自有项目的编号,IMAGE_NAME 是用于启动虚拟机的映像的名称。
    • isBootDisk:一个布尔标识符,用于指明此磁盘是否用作虚拟机的启动磁盘。

查找并验证控制平面虚拟机映像的 VSA

在本部分中,您将在 GitHub 上的 gke-vsa 代码库中找到与控制平面虚拟机映像对应的 VSA。然后,您可以使用软件工件的供应链级别 (SLSA) 框架提供的名为 slsa-verifier 的工具来验证 VSA。您需要从控制平面虚拟机创建日志中获取以下数据:

  • 虚拟机映像 ID
  • 托管虚拟机的 Google Cloud自有项目的项目编号
  • 用于启动虚拟机的操作系统映像名称

与控制平面虚拟机对应的文件采用以下文件名格式:

IMAGE_NAME:IMAGE_ID.intoto.jsonl

替换以下内容:

  • IMAGE_NAME:虚拟机映像名称,即上一部分中虚拟机审核日志的 attachedDisks.sourceImage 字段中 /images/ 后面的字符串。例如 gke-1302-gke1627000-cos-113-18244-85-49-c-pre
  • IMAGE_ID:虚拟机映像 ID,即上一部分中虚拟机审核日志中的 attachedDisks.sourceImageId 字段的值。例如 9046093115864736653

如需在知道 VSA 文件的文件名时查找和验证 VSA,请执行以下步骤:

  1. 打开 gke-vsa GitHub 代码库
  2. 在“gke-master-images”目录中,找到与您的虚拟机映像对应的文件。例如:https://github.com/GoogleCloudPlatform/gke-vsa/blob/main/gke-master-images:78064567238/IMAGE_NAME:IMAGE_ID.intoto.jsonl
  3. 下载 VSA 文件。
  4. 安装 slsa-verifier 工具
  5. 将用于验证 VSA 的公钥保存到名为 vsa_signing_public_key 的文件中:

    -----BEGIN PUBLIC KEY-----
    MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeGa6ZCZn0q6WpaUwJrSk+PPYEsca
    3Xkk3UrxvbQtoZzTmq0zIYq+4QQl0YBedSyy+XcwAMaUWTouTrB05WhYtg==
    -----END PUBLIC KEY-----
    

  6. 验证 VSA:

    slsa-verifier verify-vsa \
        --attestation-path=PATH_TO_VSA_FILE \
        --resource-uri=gce_image://gke-master-images:IMAGE_NAME \
        --subject-digest=gce_image_id:IMAGE_ID\
        --verifier-id=https://bcid.corp.google.com/verifier/bcid_package_enforcer/v0.1 \
        --verified-level=BCID_L1 \
        --verified-level=SLSA_BUILD_LEVEL_2 \
        --public-key-path=PATH_TO_PUBLIC_KEY_FILE \
        --public-key-id=keystore://76574:prod:vsa_signing_public_key
    

    替换以下内容:

    • PATH_TO_VSA_FILE:您下载的 VSA 文件的路径。
    • IMAGE_NAME:虚拟机映像的名称,例如 gke-1302-gke1627000-cos-113-18244-85-49-c-pre
    • IMAGE_ID:虚拟机映像 ID,例如 9046093115864736653

    如果 VSA 通过验证检查,输出如下所示:

    Verifying VSA: PASSED
    PASSED: SLSA verification passed
    

后续步骤