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

本主题介绍如何为 GKE on AWS 工作负载启用工作负载身份来控制其对 AWS 资源的访问权限。

如需了解如何将工作负载身份与 Google Cloud Identity and Access Management (IAM) 账号搭配使用,以控制对 GCP 资源的访问权限,请参阅将工作负载身份与 Google Cloud 搭配使用

概览

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

如需为集群启用工作负载身份,请完成以下步骤,这些步骤按执行它们的管理角色进行分组。

集群管理员

  1. 创建 Cloud Storage 存储分区以存储 OIDC 发现数据
  2. 创建 Identity and Access Management 角色以从该存储桶读取数据。
  3. 创建启用了 Workload Identity 的用户集群。
  4. 在集群上创建网络钩子,该网络钩子会在创建时将工作负载身份凭据应用于 Pod。如果您不想使用网络钩子,则可以在 pod 中手动设置环境变量。
  5. 配置 AWS OIDC 提供方
  6. 创建 AWS IAM 角色和政策
集群管理员或开发者
  1. 创建 Kubernetes 服务账号,并向其绑定 AWS 政策。
开发者
  1. 将凭据应用到 Pod

前提条件

如要完成本文档中的步骤,您必须进行以下设置:

  • GKE on AWS 管理服务
  • 运行高于 1.17.9 的 Kubernetes 版本的用户集群。

  • 以下权限和工具。

权限

如要创建启用了 Workload Identity 的集群,您需要以下权限:

Google Cloud

  • 创建一个可公开读取的 Cloud Storage 存储分区,并启用统一存储分区级访问权限。
  • 授予 management-sa@PROJECT_NAME.iam.gserviceaccount.com 对存储分区的读取/写入权限。

AWS

  • 创建 AWS OIDC 提供方
  • 创建 AWS IAM 角色

工具

在本地机器上,建议安装 jq 工具

创建 OIDC 发现存储分区

本部分面向集群管理员

您的用户集群需要将 OIDC 发现数据存储在可公开访问的 Cloud Storage 存储分区中。存储分区包含 OIDC 发现配置和公钥。AWS 使用这些内容验证来自用户集群的请求。

您的存储分区必须具有以下属性:

如果您没有具有这些属性的存储分区,请使用以下 gsutil 命令创建一个:

BUCKET=BUCKET_NAME
gsutil mb -b on gs://${BUCKET}
gsutil iam ch allUsers:objectViewer gs://${BUCKET}

BUCKET_NAME 替换为新存储分区的名称。

授予管理服务账号权限

GKE on AWS 管理服务的 Identity and Access Management 服务账号需要权限才能向此存储桶读取和写入对象。

  1. 使用以下 gsutil 命令向您的管理服务账号授予权限。

    MANAGEMENT_SA=management-sa@PROJECT_NAME.iam.gserviceaccount.com
    gsutil iam ch serviceAccount:${MANAGEMENT_SA}:admin gs://${BUCKET}
    

    PROJECT_NAME 替换为您的 Google Cloud 项目。

  2. 创建拥有此存储桶的管理权限的新 IAM 角色。要创建此角色,请首先将角色定义保存到一个文件中,然后创建角色并将角色绑定到您的管理服务账号。

    要完成这些步骤,请运行以下命令:

    cat << EOF >  anthos-oidc-role.yaml
    title: anthosAwsOidcStorageAdmin
    description: permissions to manage the OIDC buckets
    stage: GA
    includedPermissions:
    - storage.buckets.get
    EOF
    
    gcloud iam roles create anthosAwsOidcStorageAdmin --project=PROJECT_NAME \
      --file=anthos-oidc-role.yaml
    
    gcloud projects add-iam-policy-binding \
      PROJECT_NAME \
      --member=serviceAccount:${MANAGEMENT_SA} \
      --role=projects/PROJECT_NAME/roles/anthosAwsOidcStorageAdmin
    

    PROJECT_NAME 替换为您的 Google Cloud 项目。

    Google Cloud CLI 确认政策绑定已创建。

创建用户集群

本部分面向集群管理员

创建启用了 Workload Identity 的用户集群。

创建一个包含您的 OIDC 发现存储分区详情的用户集群。您可以在 AWSClusterspec.controlPlane.workloadIdentity.oidcDiscoveryGCSBucket 字段中设置此信息。

在此示例中,您将通过 AWSClusterAWSNodePool CRD 手动创建集群。

  1. 切换到您的 GKE on AWS 配置所在的目录。 您在安装管理服务时创建了此目录。

    cd anthos-aws

  2. anthos-aws 目录中,使用 anthos-gke 将上下文切换到管理服务。

    cd anthos-aws
    anthos-gke aws management get-credentials

  3. 打开文本编辑器并将以下 AWSCluster 定义复制到名为 custom-cluster.yaml 的文件中。

    apiVersion: multicloud.cluster.gke.io/v1
    kind: AWSCluster
    metadata:
      name: CLUSTER_NAME
    spec:
      region: AWS_REGION
      networking:
        vpcID: VPC_ID
        podAddressCIDRBlocks: POD_ADDRESS_CIDR_BLOCKS
        serviceAddressCIDRBlocks: SERVICE_ADDRESS_CIDR_BLOCKS
        ServiceLoadBalancerSubnetIDs: SERVICE_LOAD_BALANCER_SUBNETS
      controlPlane:
        version:  CLUSTER_VERSION # Latest version is 1.25.5-gke.2100
        instanceType: AWS_INSTANCE_TYPE
        keyName: SSH_KEY_NAME
        subnetIDs:
        - CONTROL_PLANE_SUBNET_IDS
        securityGroupIDs:
        - CONTROL_PLANE_SECURITY_GROUPS
        iamInstanceProfile: CONTROL_PLANE_IAM_ROLE
        rootVolume:
          sizeGiB: ROOT_VOLUME_SIZE
          volumeType: ROOT_VOLUME_TYPE # Optional
          iops: ROOT_VOLUME_IOPS # Optional
          kmsKeyARN: ROOT_VOLUME_KEY # Optional
        etcd:
          mainVolume:
            sizeGiB: ETCD_VOLUME_SIZE
            volumeType: ETCD_VOLUME_TYPE # Optional
            iops: ETCD_VOLUME_IOPS # Optional
            kmsKeyARN: ETCD_VOLUME_KEY # Optional
        databaseEncryption:
          kmsKeyARN: ARN_OF_KMS_KEY
        hub: # Optional
          membershipName: ANTHOS_CONNECT_NAME
        cloudOperations: # Optional
          projectID: YOUR_PROJECT
          location: GCP_REGION
          enableLogging: ENABLE_LOGGING
          enableMonitoring: ENABLE_MONITORING
        workloadIdentity: # Optional
          oidcDiscoveryGCSBucket: WORKLOAD_IDENTITY_BUCKET
    

    请替换以下内容:

    • CLUSTER_NAME:您的集群的名称。
    • AWS_REGION:您的集群在其中运行的 AWS 地区。

    • VPC_ID:您的集群在其中运行的 VPC 的 ID。

    • POD_ADDRESS_CIDR_BLOCKS:集群的 pod 使用的 IPv4 地址范围。目前仅支持单个范围。 此范围不得与从您的网络访问的任何子网重叠。您可以放心地在多个不同的 AWSCluster 对象中使用相同的范围。例如 10.2.0.0/16

    • SERVICE_ADDRESS_CIDR_BLOCKS:集群的服务使用的 IPv4 地址范围。目前仅支持单个范围。 此范围不得与从您的网络访问的任何子网重叠。 您可以放心地在多个不同的 AWSCluster 对象中使用相同的范围。例如 10.1.0.0/16

    • SERVICE_LOAD_BALANCER_SUBNETS:GKE on AWS 可在其中创建公共或专用负载平衡器的子网 ID。

    • CLUSTER_VERSION:GKE on AWS 支持的 Kubernetes 版本。最新版本为 1.25.5-gke.2100。

    • AWS_INSTANCE_TYPE支持的 EC2 实例类型

    • SSH_KEY_NAMEAWS EC2 密钥对

    • CONTROL_PLANE_SUBNET_IDS:您的控制层面实例在其中运行的 AZ 中的子网 ID。

    • CONTROL_PLANE_SECURITY_GROUPS:在安装管理服务期间创建的 securityGroupID。您可以通过添加连接到控制层面所需的 securityGroupID 来自定义此项。

    • CONTROL_PLANE_IAM_PROFILE:分配给控制层面副本的 AWS EC2 实例配置文件的名称。

    • ROOT_VOLUME_SIZE:控制层面根卷的大小(以 GiB 为单位)。

    • ROOT_VOLUME_TYPE 替换为 EBS 卷类型。例如 gp3

    • ROOT_VOLUME_IOPS 替换为卷的每秒预配 IO 操作数 (IOPS)。仅在 volumeTypeGP3 时有效。如需了解详情,请参阅通用 SSD 卷 (gp3)

    • ROOT_VOLUME_KEY 替换为加密您的控制层面实例根卷的 AWS KMS 密钥的 Amazon 资源名称。

    • ETCD_VOLUME_SIZE:etcd 使用的卷的大小。

    • ETCD_VOLUME_TYPE 替换为 EBS 卷类型。例如 gp3

    • ETCD_VOLUME_IOPS 替换为卷的每秒预配 IO 操作数 (IOPS)。仅在 volumeTypegp3 时有效。如需了解详情,请参阅通用 SSD 卷 (gp3)

    • ETCD_VOLUME_KEY 替换为 AWS KMS 密钥的 Amazon 资源名称,以加密您的控制层面 etcd 数据卷。

    • ARN_OF_KMS_KEY:用于加密集群 Secret 的 AWS KMS 密钥。

    • ANTHOS_CONNECT_NAME:用于注册集群的 Connect 成员资格名称。成员资格名称必须是唯一的。例如 projects/YOUR_PROJECT/locations/global/memberships/CLUSTER_NAME,其中 YOUR_PROJECT 是您的 Google Cloud 项目,CLUSTER_NAME 是项目中的唯一名称。 此字段是可选字段。

    • YOUR_PROJECT:您的项目 ID。

    • GCP_REGION:您要在其中存储日志的 Google Cloud 区域。选择 AWS 区域附近的区域。 如需了解详情,请参阅全球位置 - 区域和可用区(例如 us-central1)。

    • ENABLE_LOGGINGtruefalse,是否在控制层面节点上启用 Cloud Logging。

    • ENABLE_MONITORINGtruefalse,是否在控制层面节点上启用 Cloud Monitoring。

    • WORKLOAD_IDENTITY_BUCKET:包含您的 Workload Identity 发现信息的 Cloud Storage 存储分区名称。 此字段是可选字段。

  4. 为集群创建一个或多个 AWSNodePool。打开文本编辑器并将以下 AWSCluster 定义复制到名为 custom-nodepools.yaml 的文件中。

    apiVersion: multicloud.cluster.gke.io/v1
    kind: AWSNodePool
    metadata:
      name: NODE_POOL_NAME
    spec:
      clusterName: AWSCLUSTER_NAME
      version:  CLUSTER_VERSION # latest version is 1.25.5-gke.2100
      region: AWS_REGION
      subnetID: AWS_SUBNET_ID
      minNodeCount: MINIMUM_NODE_COUNT
      maxNodeCount: MAXIMUM_NODE_COUNT
      maxPodsPerNode: MAXIMUM_PODS_PER_NODE_COUNT
      instanceType: AWS_NODE_TYPE
      keyName: KMS_KEY_PAIR_NAME
      iamInstanceProfile: NODE_IAM_PROFILE
      proxySecretName: PROXY_SECRET_NAME
      rootVolume:
        sizeGiB: ROOT_VOLUME_SIZE
        volumeType: VOLUME_TYPE # Optional
        iops: IOPS # Optional
        kmsKeyARN: NODE_VOLUME_KEY # Optional 
    

    请替换以下内容:

    • NODE_POOL_NAME:您的 AWSNodePool 的唯一名称。
    • AWSCLUSTER_NAME:您的 AWSCluster 的名称。例如 staging-cluster
    • CLUSTER_VERSION:受支持的 GKE on AWS Kubernetes 版本
    • AWS_REGION:您的 AWSCluster 所在的 AWS 区域。
    • AWS_SUBNET_ID:您的 AWSCluster 所在的区域中的 AWS 子网。
    • MINIMUM_NODE_COUNT:节点池中的节点数下限。如需了解详情,请参阅扩缩用户集群
    • MAXIMUM_NODE_COUNT:节点池中的节点数上限。
    • MAXIMUM_PODS_PER_NODE_COUNT:GKE on AWS 可以分配给一个节点的 Pod 数上限。
    • AWS_NODE_TYPEAWS EC2 实例类型
    • KMS_KEY_PAIR_NAME:分配给每个节点池工作器的 AWS KMS 密钥对。
    • NODE_IAM_PROFILE:分配给池中节点的 AWS EC2 实例配置文件的名称。
    • ROOT_VOLUME_SIZE:控制层面根卷的大小(以 GiB 为单位)。
    • VOLUME_TYPE:节点的 AWS EBS 卷类型。例如 gp3
    • IOPS:卷的每秒预配 IO 操作数 (IOPS)。仅在 volumeTypegp3 时有效。
    • NODE_VOLUME_KEY:用于对卷进行加密的 AWS KMS 密钥的 ARN。如需了解详情,请参阅使用客户管理 CMK 来加密卷
  5. 将清单应用到您的管理服务。

    env HTTPS_PROXY=http://localhost:8118 \
      kubectl apply -f custom-cluster.yaml
    env HTTPS_PROXY=http://localhost:8118 \
      kubectl apply -f custom-nodepools.yaml
    

创建 kubeconfig

在用户集群启动时,您可以为新用户集群创建 kubeconfig 上下文。您将使用该上下文向用户或管理集群进行身份验证。

  1. 使用 anthos-gke aws clusters get-credentials~/.kube/config 中的用户集群生成 kubeconfig

    env HTTPS_PROXY=http://localhost:8118 \
      anthos-gke aws clusters get-credentials CLUSTER_NAME
    

    CLUSTER_NAME 替换为您的集群的名称。例如 cluster-0

  2. 使用 kubectl 向新用户集群进行身份验证。

    env HTTPS_PROXY=http://localhost:8118 \
      kubectl cluster-info
    

    如果您的集群已准备就绪,则输出内容会包含集群中 Kubernetes 组件的网址。

查看集群的状态

如果您应用 AWSClusterAWSNodePool,则管理服务会预配 AWS 资源。

  1. anthos-aws 目录中,使用 anthos-gke 将上下文切换到管理服务。

    cd anthos-aws
    anthos-gke aws management get-credentials

  2. 如需列出集群,请使用 kubectl get AWSClusters

    env HTTPS_PROXY=http://localhost:8118 \
      kubectl get AWSClusters
    

    输出包括每个集群的名称、状态、存在时间、版本和端点。

    例如,以下输出仅包含一个名为 cluster-0AWSCluster

    NAME        STATE          AGE     VERSION         ENDPOINT
    cluster-0   Provisioning   2m41s   1.25.5-gke.2100   gke-xyz.elb.us-east-1.amazonaws.com
    

查看集群事件

如需查看用户集群中的近期 Kubernetes 事件,请使用 kubectl get events

  1. anthos-aws 目录中,使用 anthos-gke 将上下文切换到管理服务。

    cd anthos-aws
    anthos-gke aws management get-credentials

  2. 运行 kubectl get events

    env HTTPS_PROXY=http://localhost:8118 \
      kubectl get events
    

输出包括与您的管理服务相关的信息、警告和错误。

创建 Workload Identity Webhook

本部分面向集群管理员

如需在不进行其他配置的情况下为工作负载提供 Workload Identity 凭据,您可以视需要在用户集群上创建网络钩子。此网络钩子会拦截 Pod 创建请求,然后将以下 AWS IAM 信息作为环境变量提供给 Pod:

  • AWS_ROLE_ARN:IAM 角色的 Amazon 资源名称 (ARN)
  • aws-iam-token:用于交换 AWS IAM 凭据的令牌
  • AWS_WEB_IDENTITY_TOKEN_FILE:存储令牌的路径

通过这些变量,您的工作负载可以调用 AWS 命令行工具,或者 SDK 可以访问被授予 AWS 角色的资源。

创建网络钩子是可选操作。如果您决定不创建网络钩子,则需要设置之前在 Pod 中列出的环境变量。如需了解如何不使用网络钩子,请参阅在不使用网络钩子的情况下应用凭据

为网络钩子创建 YAML 文件

如需部署网络钩子,请执行以下步骤:

  1. anthos-aws 目录中,使用 anthos-gke 将上下文切换到管理服务。

    cd anthos-aws
    anthos-gke aws management get-credentials

  2. 使用 kubectl 获取用户集群名称:

    env HTTPS_PROXY=http://localhost:8118 \
      kubectl get awscluster
    

    kubectl 会列出所有用户集群。选择您创建的启用了 Workload Identity 的用户集群。

  3. 在环境变量中设置集群的名称。

    CLUSTER_NAME=CLUSTER_NAME
    

    CLUSTER_NAME 替换为您的集群名称。 例如 cluster-0

  4. 为 Workload Identity Pod 映像和命名空间设置环境变量。

    IDENTITY_IMAGE=amazon/amazon-eks-pod-identity-webhook:ed8c41f
    
    WEBHOOK_NAMESPACE=workload-identity-webhook
    
  5. 通过执行以下步骤,在名为 aws-webhook.yaml 的文件中生成网络钩子 YAML 清单:

    env HTTPS_PROXY=http://localhost:8118 \
      anthos-gke aws clusters get-credentials ${CLUSTER_NAME}
    
    CLUSTER_CA=$(env HTTPS_PROXY=http://localhost:8118 \
      kubectl config view --raw -o json  | jq -r '.clusters[] | select(.name == "'$(kubectl config current-context)'") | .cluster."certificate-authority-data"')
    
    cat << EOF > aws-webhook.yaml
    apiVersion: v1
    kind: Namespace
    metadata:
      name: ${WEBHOOK_NAMESPACE}
    ---
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: pod-identity-webhook
      namespace: ${WEBHOOK_NAMESPACE}
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      name: pod-identity-webhook
      namespace: ${WEBHOOK_NAMESPACE}
    rules:
      - apiGroups: ['']
        resources: ['secrets']
        verbs: ['create']
      - apiGroups: ['']
        resources: ['secrets']
        verbs: ['get', 'update', 'patch']
        resourceNames:
          - pod-identity-webhook
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      name: pod-identity-webhook
      namespace: ${WEBHOOK_NAMESPACE}
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: Role
      name: pod-identity-webhook
    subjects:
      - kind: ServiceAccount
        name: pod-identity-webhook
        namespace: ${WEBHOOK_NAMESPACE}
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      name: pod-identity-webhook
    rules:
      - apiGroups: ['']
        resources: ['serviceaccounts']
        verbs: ['get', 'watch',  'list']
      - apiGroups:  ['certificates.k8s.io']
        resources: ['certificatesigningrequests']
        verbs:  ['create', 'get', 'list', 'watch']
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: pod-identity-webhook
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: pod-identity-webhook
    subjects:
      - kind: ServiceAccount
        name: pod-identity-webhook
        namespace: ${WEBHOOK_NAMESPACE}
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: pod-identity-webhook
      namespace: ${WEBHOOK_NAMESPACE}
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: pod-identity-webhook
      template:
        metadata:
          labels:
            app: pod-identity-webhook
        spec:
          serviceAccountName: pod-identity-webhook
          containers:
            - name: pod-identity-webhook
              image: ${IDENTITY_IMAGE}
              imagePullPolicy: Always
              command:
                - /webhook
                - --in-cluster
                - --namespace=${WEBHOOK_NAMESPACE}
                - --service-name=pod-identity-webhook
                - --tls-secret=pod-identity-webhook
                - --annotation-prefix=eks.amazonaws.com
                - --token-audience=sts.amazonaws.com
                - --logtostderr
              volumeMounts:
                - name: webhook-certs
                  mountPath: /var/run/app/certs
                  readOnly: false
          volumes:
            - name: webhook-certs
              emptyDir: {}
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: pod-identity-webhook
      namespace: ${WEBHOOK_NAMESPACE}
      annotations:
        prometheus.io/port: '443'
        prometheus.io/scheme: https
        prometheus.io/scrape: 'true'
    spec:
      ports:
        - port: 443
          targetPort: 443
      selector:
        app: pod-identity-webhook
    ---
    apiVersion: admissionregistration.k8s.io/v1
    kind: MutatingWebhookConfiguration
    metadata:
      name: pod-identity-webhook
      namespace: ${WEBHOOK_NAMESPACE}
    webhooks:
      - name: pod-identity-webhook.amazonaws.com
        failurePolicy: Ignore
        sideEffects: 'None'
        admissionReviewVersions: ['v1beta1']
        clientConfig:
          service:
            name: pod-identity-webhook
            namespace: ${WEBHOOK_NAMESPACE}
            path: /mutate
          caBundle: ${CLUSTER_CA}
        rules:
          - operations: ['CREATE']
            apiGroups: ['']
            apiVersions: ['v1']
            resources: ['pods']
    EOF
    

    现在可以将 aws-webhook.yaml 的内容应用到您的集群了。

将网络钩子应用到用户集群

如需将网络钩子应用到您的用户集群,请执行以下步骤。

  1. aws-webhook.yaml 文件应用到用户集群。

    env HTTPS_PROXY=http://localhost:8118 \
      kubectl apply -f aws-webhook.yaml
    
  2. 应用清单时,网络钩子 Pod 将生成 Kubernetes 证书签名请求 (CSR)。使用 kubectl certificate approve 批准来自 system:serviceaccount:${WEBHOOK_NAMESPACE}:pod-identity-webhook 的所有请求。

    env HTTPS_PROXY=http://localhost:8118 \
      kubectl certificate approve $(env HTTPS_PROXY=http://localhost:8118 \ &&\
      kubectl get csr -o \
        jsonpath="{.items[?(@.spec.username==\"system:serviceaccount:${WEBHOOK_NAMESPACE}:pod-identity-webhook\")].metadata.name}")
    
  3. 确认没有未获批准的 CSR。

    使用 kubectl get csr 检查来自请求者 system:serviceaccount:${WEBHOOK_NAMESPACE}:pod-identity-webhook 的 CSR 是否都已获得批准:

    env HTTPS_PROXY=http://localhost:8118 \
      kubectl get csr
    

    响应:

    NAME        AGE   REQUESTOR                                            CONDITION
    csr-mxrt8   10s   system:serviceaccount:default:pod-identity-webhook   Approved,Issued
    

配置 AWS OIDC 提供方

本部分面向集群管理员

若要在 AWS 中创建 OIDC 提供方,AWS 要求使用中间证书授权机构 (CA) 或服务器证书指纹。您的 OIDC 发现凭据存储在 storage.googleapis.com 上,该证书由一个名为 GTS CA 1C3 的中间 CA 签名。其中间 CA GTS CA 1C3 的 SHA-1 指纹为 08745487E891C19E3078C1F2A07E452950EF36F6

如要将 OIDC 发现存储分区注册为 AWS 的 OIDC 提供方,请执行以下步骤:

  1. anthos-aws 目录中,使用 anthos-gke 将上下文切换到管理服务。

    cd anthos-aws
    anthos-gke aws management get-credentials

  2. 将 OIDC 颁发者网址、颁发者主机路径和 Cloud Storage Thumbprint 保存在环境变量中。

    ISSUER_URL=$(env HTTPS_PROXY=http://localhost:8118 \
      kubectl get awscluster ${CLUSTER_NAME} -o jsonpath='{.status.workloadIdentityInfo.issuerURL}')
    ISSUER_HOSTPATH=${ISSUER_URL#"https://"}
    CA_THUMBPRINT=08745487E891C19E3078C1F2A07E452950EF36F6
    
  3. 使用 aws 命令行工具,在 AWS 上创建 OIDC 提供方。

    aws iam create-open-id-connect-provider \
      --url ${ISSUER_URL} \
      --thumbprint-list ${CA_THUMBPRINT} \
      --client-id-list sts.amazonaws.com
    

更新指纹

如果 Google 轮替 storage.googleapis.com 的 CA,请运行以下命令:

  1. 复制更新后的证书指纹 08745487E891C19E3078C1F2A07E452950EF36F6

  2. 按照 aws iam update-open-id-connect-provider-thumbprint 命令的说明进行操作。使用 storage.googleapis.com 作为目标主机名,并使用 08745487E891C19E3078C1F2A07E452950EF36F6 作为指纹。

创建 AWS IAM 角色和政策

本部分面向集群管理员

创建要绑定到 Kubernetes 服务账号的 AWS IAM 角色。IAM 角色拥有 sts:AssumeRoleWithWebIdentity 的权限。

要创建角色,请执行以下步骤:

  1. 查找或创建可为您的工作负载授予必要权限的 AWS IAM 政策

    您需要政策的 Amazon 资源名称 (ARN) AWS IAM 政策。例如 arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess

  2. 使用您的身份验证信息设置环境变量。

    KSA_NAME=KUBERNETES_SERVICE_ACCOUNT
    WORKLOAD_NAMESPACE=WORKLOAD_IDENTITY_NAMESPACE
    
    AWS_ROLE_NAME=AWS_ROLE_NAME
    AWS_POLICY=EXISTING_AWS_POLICY
    

    请替换以下内容:

    • KUBERNETES_SERVICE_ACCOUNT:新 Kubernetes 服务账号的名称
    • WORKLOAD_IDENTITY_NAMESPACE:运行工作负载的命名空间的名称
    • AWS_ROLE_NAME:工作负载的新 AWS 角色的名称
    • EXISTING_AWS_POLICY:现有 AWS IAM 政策的 Amazon 资源名称 (ARN),例如 arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
  3. anthos-aws 目录中,使用 anthos-gke 将上下文切换到管理服务。

    cd anthos-aws
    anthos-gke aws management get-credentials

  4. 创建一个 AWS IAM 政策,该政策允许您的用户群集通过 AWS Security Token Service 采用临时安全凭证:

    CLUSTER_ID=$(env HTTPS_PROXY=http://localhost:8118 \
      kubectl get awscluster ${CLUSTER_NAME} -o jsonpath='{.status.clusterID}')
    
    # Get the ID Provider ARN
    PROVIDER_ARN=$(aws iam list-open-id-connect-providers  \
    | jq '.OpenIDConnectProviderList' \
    | jq ".[] | select(.Arn |  contains(\"${CLUSTER_ID}\"))"   \
    | jq  '.Arn' | tr -d '"')
    
    # Create AWS role and policy
    cat > irp-trust-policy.json << EOF
    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Principal": {
            "Federated": "${PROVIDER_ARN}"
          },
          "Action": "sts:AssumeRoleWithWebIdentity",
          "Condition": {
            "StringEquals": {
              "${ISSUER_HOSTPATH}:sub": "system:serviceaccount:${WORKLOAD_NAMESPACE}:${KSA_NAME}"
            }
          }
        }
      ]
    }
    EOF
    
  5. 如需创建具有此政策的 AWS IAM 角色并将现有政策关联到该角色,请运行以下命令:

    aws iam create-role \
      --role-name ${AWS_ROLE_NAME} \
      --assume-role-policy-document file://irp-trust-policy.json
    aws iam update-assume-role-policy \
      --role-name ${AWS_ROLE_NAME} \
      --policy-document file://irp-trust-policy.json
    aws iam attach-role-policy \
      --role-name ${AWS_ROLE_NAME} \
      --policy-arn ${AWS_POLICY}
    

    aws 命令行工具可确认政策已关联到您的角色。

为工作负载创建 Kubernetes 服务账号

本部分面向开发者或集群管理员

如需创建绑定到之前指定的 AWS IAM 角色的 Kubernetes 服务账号,请执行以下步骤:

  1. anthos-aws 目录中,使用 anthos-gke 将上下文切换到用户集群。

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

  2. 运行以下命令来创建 Kubernetes 服务账号:

    S3_ROLE_ARN=$(aws iam get-role \
      --role-name AWS_ROLE_NAME \
      --query Role.Arn --output text)
    
    cat << EOF  > k8s-service-account.yaml
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: ${KSA_NAME}
      namespace: WORKLOAD_IDENTITY_NAMESPACE
    EOF
    
    env HTTPS_PROXY=http://localhost:8118 \
    kubectl apply -f k8s-service-account.yaml
    
    env HTTPS_PROXY=http://localhost:8118 \
    kubectl annotate sa --namespace ${WORKLOAD_NAMESPACE} ${KSA_NAME} eks.amazonaws.com/role-arn=${S3_ROLE_ARN}
    

    请替换以下内容:

    • AWS_ROLE_NAME:应用于您的工作负载的 AWS IAM 角色的名称
    • WORKLOAD_IDENTITY_NAMESPACE:运行工作负载的命名空间的名称

将凭据应用于 Pod

本部分面向开发者

本部分假定您已部署 Workload Identity 网络钩子。如果您尚未部署网络钩子,请跳至再没有网络钩子的情况下应用凭据

使用网络钩子应用凭据

本部分介绍如何配置 Pod 以读取网络钩子提供的凭据。

将服务账号添加到 Pod

如需将 Workload Identity 用于工作负载,请将 Kubernetes 服务账号添加到以下字段:

  • 对于 Deployment:spec.template.spec.serviceAccountName
  • 对于 Pod:spec.serviceAccount

以下 Pod 清单可启动基本 CentOS 映像并包含 spec.serviceAccount 字段。

apiVersion: v1
kind: Pod
metadata:
  name: sample-centos-pod
  namespace: WORKLOAD_IDENTITY_NAMESPACE
spec:
  containers:
  - command:
    - /bin/bash
    - -ec
    - while :; do echo '.'; sleep 500 ; done
    image: amazon/aws-cli
    name: centos
  serviceAccount: KUBERNETES_SERVICE_ACCOUNT

请替换以下内容:

  • WORKLOAD_IDENTITY_NAMESPACE:运行工作负载的命名空间的名称
  • KUBERNETES_SERVICE_ACCOUNT:您之前创建的 Kubernetes 服务账号的名称

检查 Pod 是否设置了环境变量

如需检查 Pod 是否设置了环境变量,请运行以下命令获取 Pod 的信息:

kubectl get pod --namespace WORKLOAD_IDENTITY_NAMESPACE POD_NAME -o yaml

请替换以下内容:

  • WORKLOAD_IDENTITY_NAMESPACE:运行工作负载的命名空间的名称
  • POD_NAME:要检查的 Pod 的名称

输出包含 spec.containers.command.env 中的环境变量值和 AWS IAM 令牌的装载点。以下是一个 Pod 清单示例。

apiVersion: v1
kind: Pod
metadata:
  ...
spec:
  containers:
  - command:
    - /bin/bash
    - -ec
    - while :; do echo '.'; sleep 500 ; done
    env:
    - name: AWS_ROLE_ARN
      value: arn:aws:iam::1234567890:role/my-example-workload-role-1
    - name: AWS_WEB_IDENTITY_TOKEN_FILE
      value: /var/run/secrets/eks.amazonaws.com/serviceaccount/token
    image: amazon/aws-cli
    imagePullPolicy: IfNotPresent
    name: centos
    resources: {}
    terminationMessagePath: /dev/termination-log
    terminationMessagePolicy: File
    volumeMounts:
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: my-k8s-serviceaccount-token-d4nz4
      readOnly: true
    - mountPath: /var/run/secrets/eks.amazonaws.com/serviceaccount
      name: aws-iam-token
      readOnly: true
  serviceAccount: my-k8s-serviceaccount
  serviceAccountName: my-k8s-serviceaccount
  volumes:
  - name: aws-iam-token
    projected:
      defaultMode: 420
      sources:
      - serviceAccountToken:
          audience: sts.amazonaws.com
          expirationSeconds: 86400
          path: token
  - name: my-k8s-serviceaccount-token-d4nz4
    secret:
      defaultMode: 420
      secretName: my-k8s-serviceaccount-token-d4nz4
   ...
status:
  ...

再没有网络钩子的情况下应用凭据

如果您未部署 Workload Identity 网络钩子,则需要执行以下操作:

使用 Workload Identity 的凭据创建 Pod

如需创建包含 Workload Identity 必要凭据的 Pod,请执行以下步骤:

  1. 将以下 Pod 清单复制到名为 sample-pod-no-webhook.yaml 的文件中。该配置将启动具有必需凭据的基本 CentOS 映像。

    apiVersion: v1
    kind: Pod
    metadata:
      name: sample-centos-pod-no-webhook
      namespace: WORKLOAD_IDENTITY_NAMESPACE
    spec:
      containers:
      - command:
        - /bin/bash
        - -ec
        - while :; do echo '.'; sleep 500 ; done
        image: centos:7
        name: centos
        env:
        - name: AWS_ROLE_ARN
          value: IAM_ROLE_ARN
        - name: AWS_WEB_IDENTITY_TOKEN_FILE
          value: /var/run/secrets/eks.amazonaws.com/serviceaccount/token
        volumeMounts:
        - mountPath: /var/run/secrets/eks.amazonaws.com/serviceaccount
          name: aws-iam-token
          readOnly: true
      volumes:
      - name: aws-iam-token
        projected:
          defaultMode: 420
          sources:
          - serviceAccountToken:
              audience: sts.amazonaws.com
              expirationSeconds: 86400
              path: token
      serviceAccount: KUBERNETES_SERVICE_ACCOUNT
    

    请替换以下内容:

    • WORKLOAD_IDENTITY_NAMESPACE:运行工作负载的命名空间的名称。
    • IAM_ROLE_ARN:授予 Pod 的 IAM 角色的 ARN。例如 arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
    • KUBERNETES_SERVICE_ACCOUNT:您之前创建的 Kubernetes 服务账号的名称。
  2. 使用 kubectl 将 Pod 清单应用于您的集群:

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

检查 Pod 能否访问 AWS 资源

以下过程介绍了如何检查 Pod 是否收到了 Workload Identity 正常运行所需的凭据。

如要完成这些步骤,您需要满足以下条件:

  • 拥有容器的 bash shell 访问权限;大多数生产映像都没有 shell。以下示例展示了如何使用上一部分中指定的 Pod 来访问 AWS S3。

  • 您的 Pod 需要具有对互联网的出站访问权限才能下载 AWS 命令行界面。

如需检查 Pod 能否访问 S3 存储分区,请执行以下步骤:

  1. 使用 kubectl exec 在 Pod sample-centos-pod-no-webhook 上启动交互式 bash shell:

    env HTTPS_PROXY=http://localhost:8118 \
      kubectl exec -it --namespace ${WORKLOAD_NAMESPACE} sample-centos-pod-no-webhook -- bash
    

    您的终端会打开 Pod 上的 bash shell。

  2. 使用 aws 工具检查 AWS IAM 权限和凭据:

    aws sts assume-role-with-web-identity \
     --role-arn ${AWS_ROLE_ARN} \
     --role-session-name mh9test \
     --web-identity-token file:///var/run/secrets/eks.amazonaws.com/serviceaccount/token \
     --duration-seconds 1000
    

    aws 工具会输出与以下内容类似的凭据信息:

    {
        "AssumedRoleUser": {
            "AssumedRoleId": "AROAR2ZZZLEXVSDCDJ37N:mh9test",
            "Arn": "arn:aws:sts::126285863215:assumed-role/my-example-workload-role-1/mh9test"
        },
        "Audience": "sts.amazonaws.com",
        "Provider": "arn:aws:iam::126285863215:oidc-provider/storage.googleapis.com/gke-issuer-cec6c353",
        "SubjectFromWebIdentityToken": "system:serviceaccount:default:my-s3-reader-ksa",
        "Credentials": {
            "SecretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
            "SessionToken": "MY_TOKEN",
            "Expiration": "2020-08-14T22:46:36Z",
            "AccessKeyId": "AKIAIOSFODNN7EXAMPLE"
        }
    }
    

    如果您看到以下消息,请检查存储分区是否可公开访问:An error occurred (InvalidIdentityToken) when calling the AssumeRoleWithWebIdentity operation: Couldn't retrieve verification key from your identity provider, please reference AssumeRoleWithWebIdentity documentation for requirements

升级 Webhook

如果您创建了已启用 Workload Identity 的 Kubernetes 1.18 或更低版本集群且 Workload Identity 网络钩子版本为 release-0.2.2-gke.0,则在升级到 Kubernetes 1.19 之前,您必须先升级网络钩子。

如需升级网络钩子,请执行以下步骤:

  1. 通过运行以下命令确认已安装网络钩子:

    env HTTPS_PROXY=http://localhost:8118 \
      kubectl get MutatingWebhookConfiguration
    

    如果您的集群已部署 Webhook,则输出包含以下内容:

    NAME                   WEBHOOKS   AGE
    pod-identity-webhook   1          11m
    

    如果您的集群上未部署网络钩子,则可以跳过以下步骤。

  2. 如果您保存了 aws-webhook.yaml 文件,则可以删除清单。如果您没有此文件,可以手动删除网络钩子的组件。从以下文件或组件中选择。

    文件

    如果您仍有 aws-webhook.yaml 文件,请运行以下命令删除网络钩子:

    env HTTPS_PROXY=http://localhost:8118 \
      kubectl delete -f aws-webhook.yaml
    

    组件

    如需手动删除网络钩子的组件,请运行以下命令:

    env HTTPS_PROXY=http://localhost:8118 \
       kubectl delete namespace WEBHOOK_NAMESPACE
    env HTTPS_PROXY=http://localhost:8118 \
       kubectl delete clusterrole pod-identity-webhook
    env HTTPS_PROXY=http://localhost:8118 \
       kubectl delete clusterrolebinding pod-identity-webhook
    env HTTPS_PROXY=http://localhost:8118 \
       kubectl delete mutatingwebhookconfiguration pod-identity-webhook
    

    WEBHOOK_NAMESPACE 替换为您在其中安装 Workload Identity 网络钩子的命名空间。例如 workload-identity-webhook

  3. 通过运行以下命令检查是否有任何剩余的证书签名请求 (CSR):

    env HTTPS_PROXY=http://localhost:8118 \
      kubectl get csr |grep pod-identity-webhook
    

    如果输出为空,则跳到下一步。如果存在任何其余 CSR,kubectl 命令将列出现有 CSR。如需移除 CSR,请运行以下命令:

    env HTTPS_PROXY=http://localhost:8118 \
      kubectl delete csr $(kubectl get csr -o \
      jsonpath="{.items[?(@.spec.username==\"system:serviceaccount:WEBHOOK_NAMESPACE:pod-identity-webhook\")].metadata.name}")
    

    WEBHOOK_NAMESPACE 替换为您在其中安装 Workload Identity 网络钩子的命名空间。例如 workload-identity-webhook

  4. 按照创建 Webhook 中的步骤部署新的 Webhook 版本。

    部署新的 Webhook 版本后,您需要重启使用 Webhook 的 Pod。您可以通过升级用户集群来重启您的 Pod。

清理

本部分介绍了如何移除本文档前面部分中创建的资源。

清理服务账号及其关联的 IAM 角色

如要删除服务账号及其关联的 IAM 角色,请执行以下步骤:

  1. 清理服务账号:

    env HTTPS_PROXY=http://localhost:8118 \
      kubectl delete sa KUBERNETES_SERVICE_ACCOUNT --namespace WORKLOAD_IDENTITY_NAMESPACE
    

    请替换以下内容:

    • KUBERNETES_SERVICE_ACCOUNT:新 Kubernetes 服务账号的名称
    • WORKLOAD_IDENTITY_NAMESPACE:运行工作负载的命名空间的名称
  2. 清理 AWS IAM 角色。从下列选项中选择一项:

    • 使用 AWS 控制台删除 AWS IAM 角色。

    • 在 AWS 命令行工具中使用以下命令删除角色:

      aws iam  detach-role-policy \
        --role-name=${AWS_ROLE_NAME} \
        --policy-arn=${AWS_POLICY}
      aws iam delete-role --role-name=${AWS_ROLE_NAME}
      

删除您的用户集群

如要删除您的用户集群,请执行卸载 GKE on AWS 中的步骤。

清理 AWS OIDC 提供商

删除用户集群后,您可以使用以下 bash shell 命令或 AWS 控制台在 AWS 上取消注册并删除 OIDC 提供方。

  1. anthos-aws 目录中,使用 anthos-gke 将上下文切换到管理服务。

    cd anthos-aws
    anthos-gke aws management get-credentials

  2. 在 AWS 命令行工具中使用以下命令删除角色:

    CLUSTER_ID=$(env HTTPS_PROXY=http://localhost:8118 \
      kubectl get awscluster ${CLUSTER_NAME} -o jsonpath='{.status.clusterID}')
    
    PROVIDER_ARN=$(aws iam list-open-id-connect-providers  \
    | jq '.OpenIDConnectProviderList' \
    | jq ".[] | select(.Arn |  contains(\"${CLUSTER_ID}\"))"   \
    | jq  '.Arn' | tr -d '"')
    
    aws iam delete-open-id-connect-provider \
      --open-id-connect-provider-arn=${PROVIDER_ARN}
    

    您会收到 AWS OIDC 提供方已被删除的确认信息。

后续步骤