适用于 GKE 的工作负载身份联合简介


对于在 Google Kubernetes Engine (GKE) 上运行的工作负载,建议使用适用于 GKE 的工作负载身份联合以安全且可管理的方式访问 Google Cloud 服务。

适用于 GKE 的工作负载身份联合可通过 IAM 工作负载身份联合提供,后者为在 Google Cloud 内部和外部的环境中运行的工作负载提供身份。您可以使用 IAM 工作负载身份联合从在 AWS、Azure 和自行管理的 Kubernetes 等工作负载中运行的受支持的 Google Cloud API 安全地进行身份验证。在 GKE 中,Google Cloud 会为您管理工作负载身份池和提供方,您无需外部身份提供方。

术语

本文档介绍了 Kubernetes 服务账号Identity and Access Management (IAM) 服务账号的区别。

Kubernetes 服务账号
Kubernetes 资源,用于为 GKE pod 中运行的进程提供身份。
IAM 服务账号
允许应用对 Google Cloud API 进行授权调用的 Google Cloud 资源。

什么是适用于 GKE 的工作负载身份联合?

在 GKE 上运行的应用可能需要访问 Google Cloud API,例如 Compute Engine API、BigQuery Storage API 或 Machine Learning API。

借助适用于 GKE 的工作负载身份联合,您可以使用 IAM 政策授予 GKE 集群中的 Kubernetes 工作负载对特定 Google Cloud API 的访问权限,而无需手动配置或安全性较低的方法(例如服务账号密钥文件)。利用适用于 GKE 的工作负载身份联合,您可以为集群中的每个应用分配不同的精细身份和授权。

适用于 GKE 的工作负载身份联合不再要求使用元数据隐藏。由元数据隐藏保护的敏感元数据也受适用于 GKE 的工作负载身份联合保护。

适用于 GKE 的工作负载身份联合的工作原理

在集群上启用适用于 GKE 的工作负载身份联合时,GKE 会执行以下操作:

  • 使用以下格式为集群的 Google Cloud 项目创建固定工作负载身份池:

    PROJECT_ID.svc.id.goog
    

    工作负载身份池提供了一种命名格式,使 IAM 能够理解和信任 Kubernetes 凭据。

  • 在工作负载身份池中将 GKE 集群注册为身份提供方。

  • 部署 GKE 元数据服务器,用于拦截每个节点上来自工作负载的凭据请求。

在 Google Cloud 资源上创建 IAM 允许政策

如需使用适用于 GKE 的工作负载身份联合提供访问权限,您需要创建 IAM 允许政策,向与应用身份对应的主账号授予对特定 Google Cloud 资源的访问权限。例如,您可以向使用 database-reader Kubernetes ServiceAccount 的所有 Pod 授予 Cloud Storage 存储桶的读取权限。

如需查看支持允许政策的资源列表,请参阅接受允许政策的资源类型

您还可以通过在允许政策中设置条件来限制访问权限范围。例如,如果您只想向在 mysql 集群中使用 database-reader ServiceAccount 的 Pod 授予存储桶的读取权限,则可以在允许政策中设置该条件。如需了解如何在允许政策中使用条件,请参阅管理条件角色绑定

在 IAM 政策中引用 Kubernetes 资源

在 IAM 政策中,您可以使用 IAM 主账号标识符来选择 Kubernetes 资源以引用该资源。此标识符的语法如下:

PREFIX://iam.googleapis.com/projects/1234567890/locations/global/workloadIdentityPools/example-project.svc.id.goog/SELECTOR

在此示例中,请考虑以下字段:

  • PREFIX:必须是 principalprincipalSet,具体取决于您选择的资源。principal 适用于特定资源,例如单个 ServiceAccount。principalSet 适用于属于指定资源的多个资源,例如特定集群中的所有 Pod。
  • SELECTOR:用于选择主账号类型的字符串。例如,kubernetes.serviceaccount.uid/SERVICEACCOUNT_UID 按 UID 选择 ServiceAccount。

下表显示了 GKE 中支持的主账号类型:

主账号标识符类型 语法
使用特定 Kubernetes ServiceAccount 的所有 Pod 按名称选择 ServiceAccount:

principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/PROJECT_ID.svc.id.goog/subject/ns/NAMESPACE/sa/SERVICEACCOUNT

替换以下内容:

  • PROJECT_NUMBER:您的数值项目编号。如需获取项目编号,请参阅识别项目
  • PROJECT_ID:您的 Google Cloud 项目 ID。
  • NAMESPACE:Kubernetes 命名空间。
  • SERVICEACCOUNT:Kubernetes ServiceAccount 名称。

按 UID 选择 ServiceAccount:

principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/PROJECT_ID.svc.id.goog/kubernetes.serviceaccount.uid/SERVICEACCOUNT_UID

替换以下内容:

  • PROJECT_NUMBER:您的数值项目编号。如需获取项目编号,请参阅识别项目
  • PROJECT_ID:您的 Google Cloud 项目 ID。
  • SERVICEACCOUNT_UID:API 服务器中 ServiceAccount 对象的 UID。
特定集群中的所有 Pod

principalSet://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/PROJECT_ID.svc.id.goog/kubernetes.cluster/https://container.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/clusters/CLUSTER_NAME

替换以下内容:

  • PROJECT_NUMBER:您的数值项目编号。如需获取项目编号,请参阅识别项目
  • PROJECT_ID:您的 Google Cloud 项目 ID。
  • CLUSTER_NAME:GKE 集群的名称。
  • LOCATION:您的集群的位置。

凭据流程

当工作负载发送访问 Google Cloud API 的请求时(例如,使用 Google Cloud 客户端库时),会执行以下身份验证步骤:

  1. 应用默认凭据 (ADC) 从虚拟机上运行的 Compute Engine 元数据服务器请求 Google Cloud 访问令牌。
  2. GKE 元数据服务器会拦截令牌请求,并要求 Kubernetes API 服务器提供标识请求工作负载的 Kubernetes ServiceAccount 令牌。此凭据是由集群证书授权机构 (CA) 签名的 JSON Web 令牌 (JWT)。
  3. GKE 元数据服务器使用 Security Token Service 将 JWT 交换为引用 Kubernetes 工作负载身份的短期联合 Google Cloud 访问令牌。
  4. GKE 元数据服务器为工作负载提供联合访问令牌。

然后,工作负载可以访问其 IAM 主账号标识符有权访问的任何 Google Cloud API。

身份相同性

对于共享一个工作负载身份池的多个集群中的工作负载,如果主账号标识符中的元数据相同,则 IAM 会将这些工作负载标识为相同的工作负载。例如,如果您在两个集群中有相同的命名空间,并且在 IAM 中授予对该命名空间的访问权限,则这两个集群中该命名空间中的工作负载将获得该访问权限。您可以使用条件 IAM 政策来限制此访问权限,以便仅访问特定集群。

例如,请考虑下面的图表。集群 A、B 和 C 属于同一 Google Cloud 项目,因此属于同一工作负载身份池。Google Cloud 会将集群 A 和集群 B 的 backend 命名空间中使用 back-ksa ServiceAccount 的应用识别为同一身份。IAM 不区分发出调用的集群。

说明工作负载身份池中身份相同性的示意图
使用适用于 GKE 的工作负载身份联合访问 Google Cloud API 的身份相同性

此身份相同性还意味着您必须能够信任特定工作负载身份池中的每个集群。例如,如果上述示例中的集群 C 归不受信任的团队所有,则它们可以创建 backend 命名空间,并使用 back-ksa ServiceAccount 访问 Google Cloud API,就像集群 A 和集群 B 那样。

为了避免不受信任的访问,请将集群放在不同的项目中,以确保它们获得不同的 Workload Identity 池,或者确保命名空间名称彼此不同,以避免使用共同的主账号标识符。

了解 GKE 元数据服务器

启用了适用于 GKE 的工作负载身份联合的 GKE 中的每个节点都会将其元数据存储在 GKE 元数据服务器上。GKE 元数据服务器是 Kubernetes 工作负载所需的 Compute Engine 元数据服务器端点的子集。

GKE 元数据服务器作为 DaemonSet 运行,在每个 Linux 节点上运行一个 Pod,或者在集群中的每个 Windows 节点上运行一个原生 Windows 服务。元数据服务器会拦截对 http://metadata.google.internal (169.254.169.254:80) 的 HTTP 请求。例如,GET /computeMetadata/v1/instance/service-accounts/default/token 请求将会检索 Pod 已配置为进行模拟的 IAM 服务账号的令牌。指向 GKE 元数据服务器的流量绝不会离开托管 Pod 的虚拟机实例。

下表介绍了 GKE 元数据服务器可用的 Compute Engine 元数据服务器端点的子集。如需查看 Compute Engine 元数据服务器中可用的端点的完整列表,请参阅默认虚拟机元数据值

实例元数据

实例元数据存储在以下目录下。

http://metadata.google.internal/computeMetadata/v1/instance/

条目 说明
hostname

节点的主机名。

id

节点的唯一 ID。

service-accounts/

与节点关联的服务账号的目录。对于每个服务账号,系统会提供以下信息:

  • aliases
  • email:服务账号电子邮件地址。
  • identity:节点独有的 JSON Web 令牌 (JWT)。 您必须在请求中包含 audience 参数。例如 ?audience=http://www.example.com
  • scopes:分配给服务账号的访问权限范围。
  • token:用于对工作负载进行身份验证的 OAuth 2.0 访问令牌。
zone

GKE 节点的 Compute Engine 可用区。

实例特性

实例特性存储在以下目录下。

http://metadata.google.internal/computeMetadata/v1/instance/attributes/

条目 说明
cluster-location

集群的 Compute Engine 可用区或区域。

cluster-name

GKE 集群的名称。

cluster-uid

GKE 集群的 UID。

项目元数据

集群项目元数据存储在以下目录下。

http://metadata.google.internal/computeMetadata/v1/project/

条目 说明
project-id

您的 Google Cloud 项目 ID。

numeric-project-id

您的 Google Cloud 项目编号。

适用于 GKE 的工作负载身份联合的限制

  • 您无法更改 GKE 为 Google Cloud 项目创建的工作负载身份池的名称。

  • 当 GKE 在节点池上启用 GKE 元数据服务器时,Pod 将无法再访问 Compute Engine 元数据服务器。相反,GKE 元数据服务器会拦截从这些 pod 向元数据端点发出的请求,但主机网络上运行的 Pod 除外。

  • GKE 元数据服务器需要几秒钟的时间才能开始接受新创建的 Pod 发出的请求。因此,尝试在 Pod 生命周期的前几秒内使用适用于 GKE 的工作负载身份联合进行身份验证可能会失败。重试调用会解决问题。如需了解详情,请参阅问题排查

  • GKE 内置的日志记录和监控代理将继续使用节点的服务账号

  • 适用于 GKE 的工作负载身份联合需要手动设置 Cloud Run for Anthos 才能继续发布请求指标

  • 适用于 GKE 的工作负载身份联合将每个节点的 GKE 元数据服务器连接限制为 200 个,以避免内存问题。如果您的节点数超出此限制,则可能会遇到超时情况。

  • Windows Server 节点的适用于 GKE 的工作负载身份联合可在 GKE 版本 1.18.16-gke.1200、1.19.8-gke.1300、1.20.4-gke.1500 及更高版本中使用。

  • GKE 元数据服务器的内存资源用量与集群中的 Kubernetes 服务账号总数成正比。如果您的集群拥有超过 3000 个 Kubernetes 服务账号,则 kubelet 可能会终止元数据服务器 Pod。如需了解缓解措施,请参阅问题排查

适用于 GKE 的工作负载身份联合的替代方案

您可以使用适用于 GKE 的工作负载身份联合的以下任一替代方案从 GKE 访问 Google Cloud API。我们建议您使用适用于 GKE 的工作负载身份联合,因为这些替代方案要求您做出特定的安全妥协。

后续步骤