排查特权 Autopilot 工作负载和许可名单方面的问题

Google Kubernetes Engine (GKE) Autopilot 集群中的特权工作负载必须正确配置,以避免出现问题。配置错误可能会导致与许可清单的同步失败,或导致工作负载被拒绝。这些问题可能会阻止必要的代理或服务以必要的权限运行。

使用本文档排查在 Autopilot 上部署特权工作负载时遇到的问题。查找有关如何解决许可清单同步错误的指导,并诊断特权工作负载可能遭拒的原因。

对于在 Autopilot 集群上部署具有提升权限的工作负载的平台管理员、运维人员和安全团队来说,此信息非常重要。如需详细了解我们在 Google Cloud 内容中提及的常见角色和示例任务,请参阅常见的 GKE 用户角色和任务

许可名单同步问题

当您部署 AllowlistSynchronizer 时,GKE 会尝试安装并同步您指定的许可名单文件。如果此同步失败,AllowlistSynchronizer 的 status 字段会报告错误。

获取 AllowlistSynchronizer 对象的状态:

kubectl get allowlistsynchronizer ALLOWLIST_SYNCHRONIZER_NAME -o yaml

ALLOWLIST_SYNCHRONIZER_NAME 替换为 AllowlistSynchronizer 的名称。

输出类似于以下内容:

...
status:
  conditions:
  - type: Ready
    status: "False"
    reason: "SyncError"
    message: "some allowlists failed to sync: example-allowlist-1.yaml"
    lastTransitionTime: "2024-10-12T10:00:00Z"
    observedGeneration: 2
  managedAllowlistStatus:
    - filePath: "gs://path/to/allowlist1.yaml"
      generation: 1
      phase: Installed
      lastSuccessfulSync: "2024-10-10T10:00:00Z"
    - filePath: "gs://path/to/allowlist2.yaml"
      phase: Failed
      lastError: "Initial install failed: invalid contents"
      lastSuccessfulSync: "2024-10-08T10:00:00Z"

conditions.message 字段和 managedAllowlistStatus.lastError 字段会提供有关错误的详细信息。请使用此信息来解决问题。

多个 AllowlistSynchronizer

在版本低于 1.33.4-gke.1035000 的 GKE 集群中,如果存在多个 AllowlistSynchronizerWorkloadAllowlists 可能无法安装。

如需解决此问题,请仅使用包含多个 allowlistPaths 的单个 AllowlistSynchronizer

或者,您也可以将集群升级到较新版本。

工作负载容器排序

在版本低于 1.34.0-gke.0000000 的 GKE 集群中,如果一个或多个工作负载容器映像与集群内 WorkloadAllowlist 中指定的容器映像匹配,则工作负载容器可能会以反向字母顺序进行创建和排序。

如需解决此问题,请尝试以下选项:

  • 将集群升级到 1.34.0-gke.0000000 版或更高版本。
  • 重命名工作负载的容器,以便它们按正确的顺序排序。

特权工作负载部署问题

成功安装许可名单后,您可以在集群中部署相应的特权工作负载。在某些情况下,GKE 可能会拒绝工作负载。

请尝试以下解决方案:

  • 确保集群的 GKE 版本符合工作负载的版本要求。
  • 确保您要部署的工作负载是许可名单文件所应用的工作负载。

如需了解特权工作负载遭拒的原因,请向 GKE 请求有关许可名单违规行为的详细信息:

  1. 获取集群中已安装的许可名单列表:

    kubectl get workloadallowlist
    

    找到应该应用于特权工作负载的许可名单的名称。

  2. 在文本编辑器中打开特权工作负载的 YAML 清单。如果您无法访问 YAML 清单,例如,如果工作负载部署流程使用其他工具,请与工作负载提供商联系以提交问题。跳过其余步骤。

  3. 将以下标签添加到特权工作负载 Pod 规范的 spec.metadata.labels 部分:

    labels:
      cloud.google.com/matching-allowlist: ALLOWLIST_NAME
    

    ALLOWLIST_NAME 替换为您在上一步中获得的许可名单名称。使用 kubectl get workloadallowlist 命令输出中的名称,而不是许可名单文件的路径。

  4. 保存清单并将工作负载应用于集群:

    kubectl apply -f WORKLOAD_MANIFEST_FILE
    

    WORKLOAD_MANIFEST_FILE 替换为清单文件的路径。

    输出会详细说明工作负载中的哪些字段与指定的许可名单不匹配,如下例所示:

    Error from server (GKE Warden constraints violations): error when creating "STDIN": admission webhook "warden-validating.common-webhooks.networking.gke.io" denied the request:
    
    ===========================================================================
    Workload Mismatches Found for Allowlist (example-allowlist-1):
    ===========================================================================
    HostNetwork Mismatch: Workload=true, Allowlist=false
    HostPID Mismatch: Workload=true, Allowlist=false
    Volume[0]: data
             - data not found in allowlist. Verify volume with matching name exists in allowlist.
    Container[0]:
    - Envs Mismatch:
            - env[0]: 'ENV_VAR1' has no matching string or regex pattern in allowlist.
            - env[1]: 'ENV_VAR2' has no matching string or regex pattern in allowlist.
    - Image Mismatch: Workload=k8s.gcr.io/diff/image, Allowlist=k8s.gcr.io/pause2. Verify that image string or regex match.
    - SecurityContext:
            - Capabilities.Add Mismatch: the following added capabilities are not permitted by the allowlist: [SYS_ADMIN SYS_PTRACE]
    - VolumeMount[0]: data
            - data not found in allowlist. Verify volumeMount with matching name exists in allowlist.
    

    在此示例中,存在以下违规行为:

    • 工作负载指定了 hostNetwork: true,但许可名单未指定 hostNetwork: true
    • 工作负载指定了 hostPID: true,但许可名单未指定 hostPID: true
    • 工作负载指定了一个名为 data 的卷,但许可名单未指定名为 data 的卷。
    • 容器指定了名为 ENV_VAR1ENV_VAR2 的环境变量,但许可名单未指定这些环境变量。
    • 容器指定了映像 k8s.gcr.io/diff/image,但许可名单指定了 k8s.gcr.io/pause2
    • 容器添加了 SYS_ADMINSYS_PTRACE 功能,但许可名单不允许添加这些功能。
    • 容器指定了名为 data 的卷装载,但许可名单未指定名为 data 的卷装载。

如果您要部署由第三方提供商提供的工作负载,请向该提供商提交问题以解决违规问题。提供上一步中问题的输出。

GKE 版本不兼容

如果许可名单指定的最低 GKE 版本高于集群 GKE 版本,GKE 可能会拒绝工作负载。

  1. 检查许可名单是否指定了最低 GKE 版本:

    kubectl describe workloadallowlist ALLOWLIST_NAME | grep "minGKEVersion"
    

    ALLOWLIST_NAME 替换为许可名单的名称。

    如果输出为空,则表示许可名单未指定最低 GKE 版本。跳过此部分。如果输出是一个值,则表示许可名单指定了最低 GKE 版本。

  2. 检查集群 GKE 版本:

    gcloud container clusters describe CLUSTER_NAME \
        --location=CLUSTER_LOCATION \
        --format="value(currentMasterVersion)"
    

    替换以下内容:

    • CLUSTER_NAME:集群的名称。
    • CLUSTER_LOCATION:集群的位置。 Google Cloud

    输出类似于以下内容:

    1.32.3-gke.1006000
    
  3. 如果集群的 GKE 版本低于许可名单的最低 GKE 版本,请将集群升级到许可名单的最低 GKE 版本或更高版本。如需了解更多 信息,请参阅 升级集群

升级完成后,请尝试将工作负载部署到集群。

字符串不匹配

WorkloadAllowlist 规范中的特定字段必须与工作负载规范中的相应字段完全匹配。

  1. 打开 WorkloadAllowlist CustomResourceDefinition (CRD) 参考页面
  2. 对于 WorkloadAllowlist 规范中的每个字段,检查 CRD 是否要求完全匹配。
  3. 对于需要完全匹配的每个字段,检查 WorkloadAllowlist 规范中的值是否与工作负载规范中的相应值匹配。

    例如,容器运行的每个命令都必须与许可名单中的命令完全匹配。任何与确切命令的偏差都会导致拒绝。

如果存在不匹配,请更新 WorkloadAllowlist 规范以与工作负载规范匹配。

正则表达式不匹配

WorkloadAllowlist 规范中的特定字段支持正则表达式匹配。

  1. 在 WorkloadAllowlist 规范中,找到指定正则表达式的字段。
  2. 确保正则表达式语法正确无误。WorkloadAllowlist CRD 支持 Google RE2 正则表达式语法。 验证您的表达式是否具有以下属性:

    • 正则表达式以 ^ 字符开头,以 $ 字符结尾。例如,^example-auth\.google\.com\/go_[a-z0-9]+\/google\/path$
    • 每个特殊字符都使用 \ 转义字符进行转义。查找多余或缺失的 \ 字符。
    • 许可名单中的映像路径不包含标记或摘要。例如, 使用 k8s.gcr.io/pause 而不是 k8s.gcr.io/pause:3.1k8s.gcr.io/pause@sha256:1234567890

修复任何正则表达式问题后,请尝试将工作负载部署到集群。

命令和实参中的转义字符

如果您不转义特殊字符,GKE 将无法匹配命令和实参。转义字符的要求取决于您应用许可名单的方式。例如,以 YAML 或 JSON 文件形式应用许可名单与使用命令行工具创建许可名单规范的转义要求不同。本部分介绍了 YAML 文件的转义要求。

转义 WorkloadAllowlist 规范的 commandsargs 字段中的每个特殊字符,即使您不使用正则表达式也是如此。 如需转义特殊字符,请使用 \ 字符,如以下示例所示:

  • 命令: kubectl describe \$\{POD_NAME\}
  • 实参: hostname \$NODE_NAME; dcgm-exporter --remote-hostengine-info \$\(NODE_IP\) --collectors /etc/dcgm-exporter/counters.csv

Webhook 干扰许可清单上的工作负载

在某些情况下,即使工作负载已正确配置,符合许可清单,GKE 仍可能会拒绝该工作负载。如果在工作负载控制器创建的 Pod 得到许可清单的许可后,集群中的另一个准入控制器 (webhook) 修改了该 Pod,则可能会出现这种情况。这些修改可能会导致 Pod 规范不再与许可清单匹配,从而导致被 GKE Warden 准入 webhook 拒绝。

此问题在将边车容器或环境变量注入到 Pod 中的第三方监控和安全代理中很常见。

最常见的症状是,虽然工作负载控制器(例如 DaemonSet 或 Deployment)已成功创建,但它未能创建任何 Pod。当您检查控制器的事件时,会看到指明 Pod 被准入 webhook 拒绝的消息。

  1. 按照特权工作负载部署问题 部分中的步骤,将 cloud.google.com/matching-allowlist 标签添加到您的 工作负载。
  2. 从工作负载的 YAML 清单中复制 spec.template
  3. 创建新的 Pod 清单,并将复制的规范粘贴到 spec 字段中。
  4. 在 Pod 清单中设置 apiVersionkindmetadata.name 字段:

    apiVersion: v1
    kind: Pod
    metadata:
      name: POD_NAME
      labels:
        cloud.google.com/matching-allowlist: ALLOWLIST_NAME
    spec:
      # Paste the content of spec.template here
    

    替换以下内容:

    • POD_NAME:测试 Pod 的名称。
    • ALLOWLIST_NAME:许可清单的名称。
  5. 应用 Pod 清单:

    kubectl apply -f YOUR_POD_MANIFEST_FILE
    

    YOUR_POD_MANIFEST_FILE 替换为 Pod 清单文件的路径。

  6. 检查上一步的输出。如果您在“工作负载不匹配”部分中看到意外的字段,例如额外的环境变量(如 DD_AGENT_HOST)、容器或卷,这强烈表明另一个 webhook 正在修改您的 Pod。

如需解决此问题,您需要配置冲突的 webhook,以将其排除,使其无法修改已列入许可清单的工作负载的 Pod。具体操作通常是向工作负载或其命名空间添加标签或注解,以向 webhook 告知它应不介入变更。例如,使用 Datadog 时,您需要向工作负载的命名空间添加 admission.datadoghq.com/enabled: "false" 标签。

请参阅您所用特定第三方软件的相关文档,了解如何从其准入控制器中排除工作负载。

通过阻止其他 webhook 修改 Pod,您可以帮助确保这些 Pod 继续符合许可清单,并成功部署到 Autopilot 集群中。

关于特权工作负载和许可名单的 bug 和功能请求

如果您运行由 GKE 合作伙伴或第三方提供商提供的特权工作负载,则该提供商负责创建、开发和维护其特权工作负载和许可名单。如果您遇到 bug 或有关于合作伙伴或第三方特权工作负载或许可名单的功能请求,请与提供商联系。

后续步骤