本指南介绍了如何使用工作负载身份联合,让 Azure Azure Service (AKS)、Amazon Elastic Kubernetes Service 或自托管的 Kubernetes 集群上运行的工作负载可以向 Google Cloud 进行身份验证。
借助 Kubernetes,您可以配置集群,以便工作负载可以从投影卷获取 Kubernetes 服务账号令牌。通过设置工作负载身份联合,您可以让工作负载使用这些 Kubernetes 服务账号令牌向 Google Cloud 进行身份验证。
如果您使用的是 GKE,请使用适用于 GKE 的工作负载身份联合,而不是配置 Workload Identity Federation。
准备工作
在配置 Workload Identity Federation 之前,请确保您的 Kubernetes 集群符合以下条件:
GKE
对于 Google Kubernetes Engine (GKE) 用户,请参阅从 GKE 工作负载向 Google Cloud API 进行身份验证。
AKS
请确保您的集群符合以下要求:
您已启用 OIDC 颁发者功能。
您必须启用此功能,以便 Workload Identity Federation 可以访问集群的 OpenID Connect 元数据和 JSON Web 密钥集 (JWKS)。
EKS
您无需在 EKS 配置中进行任何更改。
Kubernetes
请确保您的集群符合以下要求:
您运行的是 Kubernetes 1.20 或更高版本。
以前的 Kubernetes 版本使用了不同的服务账号令牌格式,该格式与本文档中的说明不兼容。
您已将
kube-apiserver
配置为支持ServiceAccount
令牌工作量预测。
集群无需通过互联网进行访问。
配置工作负载身份联合
您只需为每个 Kubernetes 集群执行这些步骤一次。然后,您可以为多个工作负载以及多个 Google Cloud 项目使用相同的工作负载身份池和提供方。
如需开始配置工作负载身份联合,请执行以下操作:
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
我们建议您
使用专用项目来管理工作负载身份池和提供方。
-
Make sure that billing is enabled for your Google Cloud project.
Enable the IAM, Resource Manager, Service Account Credentials, and Security Token Service APIs.
定义特性映射和条件
Kubernetes 服务账号令牌包含多个声明,包括:
sub
:包含 ServiceAccount 的命名空间和名称,例如system:serviceaccount:NAMESPACE:KSA_NAME
,其中NAMESPACE
是 ServiceAccount 的命名空间,KSA_NAME
是 ServiceAccount 的名称。"kubernetes.io".namespace
:包含 ServiceAccount 的命名空间。"kubernetes.io".serviceaccount.name
:包含 ServiceAccount 的名称。"kubernetes.io".pod.name
:包含 Pod 的名称。
如需在 Google Cloud 中将 sub
用作主题标识符 (google.subject
),请使用以下映射:
google.subject=assertion.sub
您也可以视需要映射其他特性。然后,您可以在授予对资源的访问权限时引用这些特性。 例如:
google.subject=assertion.sub, attribute.namespace=assertion['kubernetes.io']['namespace'], attribute.service_account_name=assertion['kubernetes.io']['serviceaccount']['name'], attribute.pod=assertion['kubernetes.io']['pod']['name']
您可以视需要定义特性条件。
属性条件是可以检查断言属性和目标属性的 CEL 表达式。如果给定凭据的特性条件评估结果为 true
,则接受凭据。否则,凭据会被拒绝。
您可以使用属性条件来限制哪些 Kubernetes ServiceAccount 可以使用工作负载身份联合获取短期有效的 Google Cloud 令牌。例如,以下条件将仅限 backend
和 monitoring
命名空间中的 Kubernetes 服务账号可以访问:
assertion['kubernetes.io']['namespace'] in ['backend', 'monitoring']
创建工作负载身份池和提供方
所需的角色
如需获得配置工作负载身份联合所需的权限,请让您的管理员为您授予项目的以下 IAM 角色:
-
Workload Identity Pool Admin (
roles/iam.workloadIdentityPoolAdmin
) -
Service Account Admin (
roles/iam.serviceAccountAdmin
)
如需详细了解如何授予角色,请参阅管理对项目、文件夹和组织的访问权限。
此外,IAM Owner (roles/owner
) 基本角色还具有配置身份联合的权限。您不应在生产环境中授予基本角色,但可以在开发或测试环境中授予这些角色。
如需创建工作负载身份池和提供方,请执行以下操作:
AKS
确定 AKS 集群的颁发者网址:
az aks show -n NAME -g RESOURCE_GROUP --query "oidcIssuerProfile.issuerUrl" -otsv
替换以下内容:
NAME
:集群的名称。RESOURCE_GROUP
:集群的资源组
该命令会输出颁发者网址。您将在后续的一个步骤中用到发卡机构网址。
如果该命令未返回发放方网址,请验证您是否已启用 OIDC 发放方功能。
创建新的工作负载身份池:
gcloud iam workload-identity-pools create POOL_ID \ --location="global" \ --description="DESCRIPTION" \ --display-name="DISPLAY_NAME"
替换以下内容:
POOL_ID
:池的唯一 ID。DISPLAY_NAME
:池的名称。DESCRIPTION
:您选择的池的说明。当您授予对池身份的访问权限时,系统会显示此说明。
将 EKS 集群添加为工作负载身份池提供方:
gcloud iam workload-identity-pools providers create-oidc PROVIDER_ID \ --location="global" \ --workload-identity-pool="POOL_ID" \ --issuer-uri="ISSUER" \ --attribute-mapping="MAPPINGS" \ --attribute-condition="CONDITIONS"
替换以下内容:
EKS
确定 EKS 集群的颁发者网址:
aws eks describe-cluster --name NAME --query "cluster.identity.oidc.issuer" --output text
将
NAME
替换为您的集群的名称。该命令会输出颁发者网址。您将在后续的一个步骤中用到发卡机构网址。
创建新的工作负载身份池:
gcloud iam workload-identity-pools create POOL_ID \ --location="global" \ --description="DESCRIPTION" \ --display-name="DISPLAY_NAME"
替换以下内容:
POOL_ID
:池的唯一 ID。DISPLAY_NAME
:池的名称。DESCRIPTION
:您选择的池的说明。当您授予对池身份的访问权限时,系统会显示此说明。
将 EKS 集群添加为工作负载身份池提供方:
gcloud iam workload-identity-pools providers create-oidc PROVIDER_ID \ --location="global" \ --workload-identity-pool="POOL_ID" \ --issuer-uri="ISSUER" \ --attribute-mapping="MAPPINGS" \ --attribute-condition="CONDITIONS"
替换以下内容:
Kubernetes
连接到您的 Kubernetes 集群,并使用
kubectl
确定集群的颁发者网址:kubectl get --raw /.well-known/openid-configuration | jq -r .issuer
您将在后续的一个步骤中用到发卡机构网址。
下载集群的 JSON Web 密钥集 (JWKS):
kubectl get --raw /openid/v1/jwks > cluster-jwks.json
在以下某个步骤中,您需要上传 JWKS,以便 Workload Identity Federation 验证集群颁发的 Kubernetes 服务账号令牌的真实性。
创建新的工作负载身份池:
gcloud iam workload-identity-pools create POOL_ID \ --location="global" \ --description="DESCRIPTION" \ --display-name="DISPLAY_NAME"
替换以下内容:
POOL_ID
:池的唯一 ID。DISPLAY_NAME
:池的名称。DESCRIPTION
:您选择的池的说明。当您授予对池身份的访问权限时,系统会显示此说明。
将 Kubernetes 集群添加为工作负载身份池提供方,并上传集群的 JWKS:
gcloud iam workload-identity-pools providers create-oidc PROVIDER_ID \ --location="global" \ --workload-identity-pool="POOL_ID" \ --issuer-uri="ISSUER" \ --attribute-mapping="MAPPINGS" \ --attribute-condition="CONDITIONS" \ --jwk-json-path="cluster-jwks.json"
替换以下内容:
授予对 Kubernetes 工作负载的访问权限
本部分介绍了如何将 Kubernetes 工作负载配置为使用 Workload Identity Federation 直接资源访问权限或服务账号模拟来访问 Google Cloud API。
您必须为需要访问 Google Cloud 的每个 Kubernetes 工作负载执行这些步骤一次。
我们建议您使用工作负载身份联合。不过,使用身份联合时,某些 API 方法可能会受到限制。如需查看限制列表,请参阅身份联合:产品和限制。
如果您的工作负载使用的这些方法存在此类限制,您可以改用 IAM 模拟。
使用 Workload Identity Federation 授予直接资源访问权限
在本部分中,您将使用 Workload Identity Federation 向 Kubernetes ServiceAccount 授予 IAM 角色,以便它可以直接访问 Google Cloud 资源。
如需创建 Kubernetes 服务账号并向其授予角色,请执行以下操作:
创建 Kubernetes ServiceAccount:
kubectl create serviceaccount KSA_NAME --namespace NAMESPACE
替换以下内容:
KSA_NAME
:ServiceAccount 的名称。NAMESPACE
:用于创建 ServiceAccount 的命名空间。
向 Kubernetes ServiceAccount 授予对 Google Cloud 资源的 IAM 访问权限。
遵循最小权限原则,我们建议您仅授予与应用必须访问的资源相关的角色。
在以下示例中,该命令会向您创建的 ServiceAccount 授予 Kubernetes Engine Cluster Viewer (
roles/container.clusterViewer
) 角色。该命令会使用您在本文档中前面部分映射的主题。gcloud projects add-iam-policy-binding projects/PROJECT_ID \ --role=roles/container.clusterViewer \ --member=principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/subject/MAPPED_SUBJECT \ --condition=None
替换以下内容:
PROJECT_NUMBER
:与您的项目 ID 关联的 Google Cloud 项目数字编号。POOL_ID
:工作负载身份池 ID。MAPPED_SUBJECT
:来自您已映射到google.subject
的 ID 令牌中的声明的 Kubernetes ServiceAccount。例如,如果您映射了google.subject=assertions.sub
,并且您的 ID 令牌包含"sub": "system:serviceaccount:default:my-kubernetes-serviceaccount"
,则MAPPED_SUBJECT
为system:serviceaccount:default:my-kubernetes-serviceaccount
。
您可以向支持 IAM 允许政策的任何 Google Cloud 资源授予角色。主账号标识符的语法取决于 Kubernetes 资源。如需查看支持的标识符列表,请参阅适用于 GKE 的工作负载身份联合的主账号标识符。
现在,您可以部署工作负载,让其使用 Kubernetes 服务账号来访问您已授予访问权限的 Google Cloud 资源。
替代方法:使用 IAM 服务账号模拟来授予访问权限
如需将 Kubernetes 服务账号配置为使用 IAM 服务账号模拟,请执行以下操作:
创建 Kubernetes ServiceAccount(如果您尚未创建):
kubectl create serviceaccount KSA_NAME --namespace NAMESPACE
替换以下内容:
KSA_NAME
:ServiceAccount 的名称NAMESPACE
:用于创建 ServiceAccount 的命名空间
创建一个 IAM 服务账号,以代表工作负载。
该服务账号不需要与工作负载身份池位于同一项目中,但您必须在引用该服务账号时指定包含该服务账号的项目。
gcloud iam service-accounts create IAM_SA_NAME \ --project=IAM_SA_PROJECT_ID
替换以下内容:
IAM_SA_NAME
:服务账号的名称IAM_SA_PROJECT_ID
:服务账号的项目 ID。
向您的 IAM 服务账号授予访问权限,以便其访问您希望 Kubernetes 工作负载访问的特定 Google Cloud 资源。
gcloud projects add-iam-policy-binding IAM_SA_PROJECT_ID \ --member="serviceAccount:IAM_SA_NAME@IAM_SA_PROJECT_ID.iam.gserviceaccount.com" \ --role="ROLE"
替换以下内容:
IAM_SA_PROJECT_ID
:您在其中创建服务账号的项目的 IDIAM_SA_NAME
:服务账号的名称ROLE
:包含角色名称,例如roles/container.clusterViewer
向 Kubernetes ServiceAccount 授予模拟 IAM 服务账号的访问权限:
gcloud iam service-accounts add-iam-policy-binding \ IAM_SA_NAME@IAM_SA_PROJECT_ID.iam.gserviceaccount.com \ --member="principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/subject/MAPPED_SUBJECT" \ --role=roles/iam.workloadIdentityUser
替换以下内容:
IAM_SA_NAME
:服务账号的名称PROJECT_ID
:您运行 Kubernetes 的项目的 IDIAM_SA_PROJECT_NUMBER
:您创建服务账号的项目的项目编号POOL_ID
:工作负载身份池 ID。MAPPED_SUBJECT
:来自您已映射到google.subject
的 ID 令牌中的声明的 Kubernetes ServiceAccount。例如,如果您映射了google.subject=assertions.sub
,并且您的 ID 令牌包含"sub": "system:serviceaccount:default:my-kubernetes-serviceaccount"
,则MAPPED_SUBJECT
为system:serviceaccount:default:my-kubernetes-serviceaccount
。
如需了解如何授权 IAM 服务账号访问 Google Cloud API,请参阅了解服务账号。
现在,您可以部署工作负载,让其使用 Kubernetes 服务账号和 IAM 服务账号来访问您已授予访问权限的 Google Cloud 资源。
部署 Kubernetes 工作负载
如需部署可访问 Google Cloud 资源的 Kubernetes 工作负载,请执行以下操作:
创建凭据配置文件:
gcloud iam workload-identity-pools create-cred-config \ projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/providers/PROVIDER_ID \ --service-account=SERVICE_ACCOUNT_EMAIL \ --credential-source-file=/var/run/service-account/token \ --credential-source-type=text \ --output-file=credential-configuration.json
替换以下内容:
PROJECT_NUMBER
:包含工作负载身份池的项目的编号POOL_ID
:工作负载身份池的 IDPROVIDER_ID
:工作负载身份池提供方的 IDSERVICE_ACCOUNT_EMAIL
:服务账号的电子邮件地址(如果您将 Kubernetes 服务账号配置为使用 IAM 服务账号模拟)。如果您将 Kubernetes 服务账号配置为使用直接资源访问权限,请省略此标志。
凭据配置文件可让 Cloud 客户端库、gcloud CLI 和 Terraform 确定以下内容:
- 从何处获取外部凭据
- 要使用的工作负载身份池和提供商
- 需要模拟的服务账号
将凭据配置文件导入为 ConfigMap
kubectl create configmap CONFIGMAP_NAME \ --from-file credential-configuration.json \ --namespace NAMESPACE
替换以下内容:
CONFIGMAP_NAME
:ConfigMap 的名称。NAMESPACE
:用于创建 ConfigMap 的命名空间。
部署工作负载,并让其使用 Kubernetes ServiceAccount 和 ConfigMap。
创建清单并按如下方式进行配置:
- 装载投影令牌卷,以便工作负载可以从本地文件获取 Kubernetes 服务账号令牌。配置卷,使 Kubernetes 服务账号令牌使用工作负载身份池提供程序所需的受众群体。
- 挂载包含凭据配置文件的 ConfigMap,以便工作负载可以访问使用 Workload Identity Federation 所需的配置。
- 添加包含凭据配置文件路径的环境变量
GOOGLE_APPLICATION_CREDENTIALS
,以便工作负载可以找到该文件。
以下是使用 Kubernetes ServiceAccount 和 ConfigMap 的清单示例,以便 Google Cloud CLI 对 Google Cloud 进行身份验证:
apiVersion: v1 kind: Pod metadata: name: example namespace: NAMESPACE spec: containers: - name: example image: google/cloud-sdk:alpine command: ["/bin/sh", "-c", "gcloud auth login --cred-file $GOOGLE_APPLICATION_CREDENTIALS && gcloud auth list && sleep 600"] volumeMounts: - name: token mountPath: "/var/run/service-account" readOnly: true - name: workload-identity-credential-configuration mountPath: "/etc/workload-identity" readOnly: true env: - name: GOOGLE_APPLICATION_CREDENTIALS value: "/etc/workload-identity/credential-configuration.json" serviceAccountName: KSA_NAME volumes: - name: token projected: sources: - serviceAccountToken: audience: https://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/providers/PROVIDER_ID expirationSeconds: 3600 path: token - name: workload-identity-credential-configuration configMap: name: CONFIGMAP_NAME
您可以采用相同的方法,让使用以下客户端库之一的工具和工作负载自动查找凭据:
C++
从 v2.6.0 版开始,C++ 版 Google Cloud 客户端库支持工作负载身份联合。如需使用工作负载身份联合,您必须使用 1.36.0 版或更高版本的 gRPC 构建客户端库。
Go
如果 Go 客户端库使用
golang.org/x/oauth2
模块的 v0.0.0-20210218202405-ba52d332ba99 版本或更高版本,则客户端库支持工作负载身份联合。如要查看客户端库使用的模块版本,请运行以下命令:
cd $GOPATH/src/cloud.google.com/go go list -m golang.org/x/oauth2
Java
如果 Java 客户端库使用
com.google.auth:google-auth-library-oauth2-http
工件的 0.24.0 版或更高版本,则客户端支持工作负载身份联合。如需查看该客户端库使用的工件版本,请在应用目录中运行以下 Maven 命令:
mvn dependency:list -DincludeArtifactIds=google-auth-library-oauth2-http
Node.js
如果 Node.js 版客户端库使用 7.0.2 版或更高版本的
google-auth-library
软件包,则该客户端库支持工作负载身份联合。如要查看客户端库使用的软件包版本,请在应用目录中运行以下命令:
npm list google-auth-library
创建
GoogleAuth
对象时,您可以指定项目 ID,也可以允许GoogleAuth
自动查找项目 ID。如要自动查找项目 ID,配置文件中的服务账号必须具有项目的 Browser 角色 (roles/browser
) 或具有同等权限的角色。如需了解详情,请参阅google-auth-library
软件包的README
。Python
如果 Python 客户端库使用
google-auth
软件包的 1.27.0 版本或更高版本,则客户端支持工作负载身份联合。如要检查客户端库使用的软件包版本,请在已安装该软件包的环境中运行以下命令:
pip show google-auth
如要为身份验证客户端指定项目 ID,您可以设置
GOOGLE_CLOUD_PROJECT
环境变量,也可以允许客户端自动查找项目 ID。如要自动查找项目 ID,配置文件中的服务账号必须具有项目的 Browser 角色 (roles/browser
) 或具有同等权限的角色。如需了解详情,请参阅google-auth
软件包用户指南。gcloud
如需使用工作负载身份联合进行身份验证,请使用
gcloud auth login
命令:gcloud auth login --cred-file=FILEPATH.json
将
FILEPATH
替换为凭据配置文件的路径。版本 363.0.0 及更高版本的 gcloud CLI 支持 gcloud CLI 中的工作负载身份联合。
Terraform
如果您使用 3.61.0 版或更高版本,则 Google Cloud 提供方支持工作负载身份联合:
terraform { required_providers { google = { source = "hashicorp/google" version = "~> 3.61.0" } } }
bq
如需使用工作负载身份联合进行身份验证,请使用
gcloud auth login
命令,如下所示:gcloud auth login --cred-file=FILEPATH.json
将
FILEPATH
替换为凭据配置文件的路径。390.0.0 版及更高版本的 gcloud CLI 支持 bq 中的工作负载身份联合。
(可选)运行以下命令,验证身份验证是否正常运行:
kubectl exec example --namespace NAMESPACE -- gcloud auth print-access-token
后续步骤
- 详细了解工作负载身份联合。
- 了解使用工作负载身份联合的最佳实践。
- 了解如何管理工作负载身份池和提供方。