将工作负载身份与 Google Cloud 搭配使用

本指南介绍如何在 GKE on AWS 上配置工作负载身份以控制工作负载对 GCP 资源的访问权限。其中包含一个有关如何使用身份从集群访问 Google Cloud 资源的示例。

如需了解如何将工作负载身份与 AWS IAM 账号搭配使用以控制对 AWS 资源的访问权限,请参阅将工作负载身份与 AWS 搭配使用

概览

工作负载身份使用 Google Cloud IAM 权限来控制对 Google Cloud 资源的访问权限。借助 Workload Identity,您可以为每个工作负载分配不同的 IAM 角色。通过这种精细权限控制,您可以遵循最小权限原则。 如果没有工作负载身份,您必须将 Google Cloud IAM 角色分配给 GKE on AWS 节点,从而为这些节点上的所有工作负载提供与节点本身相同的权限。

前提条件

  • 使用 Kubernetes v1.20 或更高版本创建用户集群

  • 如果您的 AWS VPC 使用代理或防火墙,请将以下网址列入许可名单:

    • securetoken.googleapis.com
    • iamcredentials.googleapis.com
    • sts.googleapis.com
  • anthos-aws 目录中,使用 anthos-gke 将上下文切换到用户集群。

    cd anthos-aws
    env HTTPS_PROXY=http://localhost:8118 \
      anthos-gke aws clusters get-credentials CLUSTER_NAME
    CLUSTER_NAME 替换为用户集群名称。

  • 使用以下命令启用此功能所需的四项新服务:

    gcloud services enable securetoken.googleapis.com
    gcloud services enable iam.googleapis.com
    gcloud services enable iamcredentials.googleapis.com
    gcloud services enable sts.googleapis.com
    

编写 WI 池和提供商名称

每个 Google Cloud 项目都会自动创建一个托管式工作负载身份池,其名称格式为 PROJECT_ID.svc.id.goog。同样,Google Cloud 会创建一个名称遵循 https://gkehub.googleapis.com/projects/PROJECT_ID/locations/global/memberships/MEMBERSHIP_ID 格式的身份提供商。如需详细了解工作负载身份池,请参阅支持队列的组件。使用您的项目 ID 和成员资格 ID 编写以下名称,如下所示:

export PROJECT_ID=USER_PROJECT_NAME
export CLUSTER_MEMBERSHIP_ID=PROJECT_MEMBERSHIP_NAME
export IDP="https://gkehub.googleapis.com/projects/${PROJECT_ID}/locations/global/memberships/${CLUSTER_MEMBERSHIP_ID}"
export WI_POOL="${PROJECT_ID}.svc.id.goog"

请替换以下内容:

  • USER_PROJECT_NAME 替换为用户选择的用户项目名称
  • PROJECT_MEMBERSHIP_NAME 替换为集群的成员资格名称

创建 IAM 政策绑定

创建政策绑定,以允许 Kubernetes 服务账号 (KSA) 模拟 Google Cloud 服务账号 (GSA)。

export K8S_NAMESPACE=KUBERNETES_NAMESPACE
export KSA_NAME=KUBERNETES_SA_NAME
export GCP_SA_EMAIL="WORKLOAD_IDENTITY_TEST@${PROJECT_ID}.iam.gserviceaccount.com"
gcloud iam service-accounts add-iam-policy-binding \
  --role roles/iam.workloadIdentityUser \
  --member "serviceAccount:$WI_POOL[$K8S_NAMESPACE/$KSA_NAME]" $GCP_SA_EMAIL

请替换以下内容:

  • KUBERNETES_NAMESPACE 替换为在其中定义了 Kubernetes 服务账号的 Kubernetes 命名空间
  • WORKLOAD_IDENTITY_TEST 替换为您选择的工作负载名称
  • KUBERNETES_SA_NAME 替换为与应用关联的 Kubernetes 服务账号的名称

创建 SDK ConfigMap

执行以下 shell 脚本,将工作负载身份详细信息存储在 ConfigMap 中。当 Pod 装载 ConfigMap 时,Google Cloud CLI 便可读取工作负载身份详细信息。

cat << EOF > cfmap.yaml
kind: ConfigMap
apiVersion: v1
metadata:
  namespace: ${K8S_NAMESPACE}
  name: my-cloudsdk-config
data:
  config: |
    {
      "type": "external_account",
      "audience": "identitynamespace:${WI_POOL}:${IDP}",
      "service_account_impersonation_url": "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/${GCP_SA_EMAIL}:generateAccessToken",
      "subject_token_type": "urn:ietf:params:oauth:token-type:jwt",
      "token_url": "https://sts.googleapis.com/v1/token",
      "credential_source": {
        "file": "/var/run/secrets/tokens/gcp-ksa/token"
      }
    }
EOF

env HTTPS_PROXY=http://localhost:8118 \
  kubectl apply -f cfmap.yaml

创建 Kubernetes 服务账号

使用与 IAM 绑定中相同的名称和命名空间在用户集群上创建 KSA。

cat << EOF > k8s-service-account.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: ${KSA_NAME}
  namespace: ${K8S_NAMESPACE}
EOF

env HTTPS_PROXY=http://localhost:8118 \
  kubectl apply -f k8s-service-account.yaml

创建 Pod

接下来,使用上文创建的服务账号令牌投影和 ConfigMap 创建 Pod。

  1. 创建示例 Pod yaml 文件。

    cat << EOF > sample-pod.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: sample-pod
      namespace: ${K8S_NAMESPACE}
    spec:
      serviceAccountName: ${KSA_NAME}
      containers:
      - command:
        - /bin/bash
        - -c
        - while :; do echo '.'; sleep 500 ; done
        image: google/cloud-sdk
        name: cloud-sdk
        env:
          - name: GOOGLE_APPLICATION_CREDENTIALS
            value: /var/run/secrets/tokens/gcp-ksa/google-application-credentials.json
        volumeMounts:
        - name: gcp-ksa
          mountPath: /var/run/secrets/tokens/gcp-ksa
          readOnly: true
      volumes:
      - name: gcp-ksa
        projected:
          defaultMode: 420
          sources:
          - serviceAccountToken:
              path: token
              audience: ${WI_POOL}
              expirationSeconds: 172800
          - configMap:
              name: my-cloudsdk-config
              optional: false
              items:
               - key: "config"
                 path: "google-application-credentials.json"
    EOF
    
  2. 将 Pod 的 YAML 应用到您的集群。

    env HTTPS_PROXY=http://localhost:8118 \
     kubectl apply -f sample-pod.yaml
    

使用 Google Cloud 工作负载身份

支持的 SDK 版本

如需使用 Google Cloud 工作负载身份功能,您必须使用支持该功能的 SDK 来构建代码。如需查看支持 Google Cloud 工作负载身份的 SDK 版本列表,请参阅队列工作负载身份

使用工作负载身份的示例代码

本部分包含使用 Google Cloud 工作负载身份的示例 Python 代码。此示例中的服务账号使用具有“Cloud Storage Admin”权限的身份来列出 Google Cloud 项目的所有 Cloud Storage 存储桶。

  1. 在 Pod 中运行 shell 命令。

    env HTTPS_PROXY=http://localhost:8118 \
    kubectl exec -it sample-pod -- bash
    
  2. 运行脚本以列出项目的存储桶。

    # execute these commands inside the Pod
    pip install --upgrade google-cloud-storage
    
    cat << EOF > sample-list-bucket.py
    from google.cloud import storage
    storage_client = storage.Client()
    buckets = storage_client.list_buckets()
    
    for bucket in buckets:
      print(bucket.name)
    EOF
    
    env GOOGLE_CLOUD_PROJECT=USER_PROJECT_NAME \
     python3 sample-list-bucket.py
    

    USER_PROJECT_NAME 替换为您的 Google Cloud 项目。

详情