從混合信任機群工作負載向 Google Cloud API 驗證身分

本頁面說明如何設定應用程式,以便從機群中驗證Google Cloud API (例如 Compute Engine API 或 AI Platform API),這些機群在整個機群中具有混合信任模型。如果車隊採用跨車隊共用信任模型,請參閱「從共用信任車隊工作負載向 API 進行驗證」。 Google Cloud

本頁面適用於平台管理員和營運人員,以及想要透過程式從車隊工作負載向 Google CloudAPI 進行驗證的安全工程師。如要進一步瞭解說明文件中提及的使用者角色和範例工作,請參閱「常見的 GKE Enterprise 使用者角色和工作」。 Google Cloud

閱讀本頁面之前,請務必熟悉下列概念:

關於混合信任環境的機群 Workload Identity 聯盟

透過 Fleet Workload Identity Federation,您可以將Google Cloud API 和資源的 IAM 角色授予機群中的實體,例如特定命名空間中的工作負載。根據預設,機群主機專案會使用 Google 管理的工作負載身分集區,為整個機群中的實體佈建身分。不過,在混合信任環境 (例如多租戶機群) 或執行獨立叢集的機群主機專案中,建議您為部分工作負載和叢集設定個別的自行管理工作負載身分集區。

使用自行管理工作負載身分集區的實體,在 IAM 政策中的 ID 與使用機群主機專案 Google 管理工作負載身分集區的實體不同。這樣一來,授予特定車隊命名空間中主體的存取權時,就不會意外授予與 ID 相符的其他主體存取權。

如要使用自行管理的工作負載身分集區,必須使用團隊範圍。團隊範圍可讓您針對個別團隊控管部分機群資源的存取權。將特定團隊範圍繫結至特定機群成員叢集,允許該團隊在這些叢集上部署工作負載。在團隊範圍內,團隊成員只能將工作負載部署至機群命名空間

使用自行管理的工作負載身分集區,為團隊範圍工作負載提供身分,可帶來以下優點:

  • 請確保授予艦隊命名空間中實體的存取權,不會無意中套用至其他命名空間或叢集中的實體。
  • 將一組機群叢集繫結至團隊範圍,並在這些叢集中將自行管理的集區設為身分識別提供者,即可設定這些叢集從自行管理的集區取得身分。
  • 設定團隊範圍的繫結叢集子集,只在特定叢集中將自行管理的集區設為身分識別提供者,即可從自行管理的集區取得身分。

混合信任環境中的身分相同性範例

請考量下列情境:

  • 您有兩個機群成員叢集:frontend-clusterfinance-cluster
  • 您尚未設定自行管理的工作負載身分集區。
  • 您可以在團隊範圍中建立finance-team團隊範圍和finance-ns機群命名空間。
  • finance-cluster 叢集繫結至 finance-team 團隊範圍。
  • 您要將 IAM 角色授予finance-sa Kubernetes finance-ns 艦隊命名空間中的 ServiceAccount。

符合下列條件的工作負載會共用相同身分:

  • finance-ns 機群命名空間中執行。
  • 使用 finance-sa ServiceAccount。

不過,如果 frontend-cluster 叢集中的使用者建立 Kubernetes 命名空間和 finance-nsfinance-sa ServiceAccount,他們會取得與 finance-cluster 叢集工作負載相同的身分。這是因為整個機群都使用機群主機專案的 Google 代管工作負載身分集區,且主體 ID 未指定主機叢集。

請考慮對上述情境進行下列變更:

  • 在 Fleet 中設定自行管理的工作負載身分集區。
  • 您會設定 finance-cluster 叢集,從自行管理的集區取得身分,而不是從 Google 管理的集區取得身分。
  • 您建立的 IAM 角色授權會指定主體 ID 中的自行管理集區,而非 Google 管理的集區。

finance-clusterfinance-ns fleet 命名空間執行的工作負載,現在會從自行管理的集區取得身分。不過,frontend-cluster 叢集中的 finance-ns Kubernetes 命名空間實體,仍會繼續從 Fleet 主機專案的 Google 管理工作負載身分集區取得身分。

這些變更可帶來以下好處:

  • 您可以在 finance-ns 艦隊命名空間中,明確授予實體角色。
  • frontend-cluster 集區中的實體無法取得相同存取權,因為 frontend-cluster 集區中的身分來自 Google 管理的工作負載身分集區。

事前準備

  • 確認您已安裝下列指令列工具:

    如果您使用 Cloud Shell 做為與 Google Cloud互動的 Shell 環境,系統會為您安裝這些工具。

  • 確認您已初始化 gcloud CLI,以便搭配專案使用。

需求條件

您必須在機群中使用機群團隊管理功能,例如團隊範圍和機群命名空間。本頁的操作說明會示範如何設定範例團隊範圍和機群命名空間。

準備您的叢集

機群中的應用程式必須先註冊至機群,並正確設定使用機群 Workload Identity Federation,才能接收聯盟身分。下列各節說明如何為不同類型的叢集設定機群 Workload Identity 聯盟。

GKE

如果是 GKE 叢集,請按照下列步驟操作:

  1. 如果尚未啟用,請在 Google Kubernetes Engine 叢集上啟用 GKE 的 Workload Identity 聯盟
  2. 向機群註冊叢集

您也可以在建立叢集和註冊車隊時,啟用 Workload Identity Federation for GKE。

外部叢集 Google Cloud

下列類型的叢集會自動啟用機群工作負載身分聯合驗證,並在建立叢集時註冊至機群:

  • VMware 上的 Google Distributed Cloud (僅限軟體)
  • 裸機上的 Google Distributed Cloud (僅限軟體)
  • GKE on AWS
  • GKE on Azure

附加的叢集

使用 GKE Multi-Cloud API 註冊的 EKS 和 AKS 附加叢集,預設會啟用機群 Workload Identity 聯盟。如果其他附加叢集符合必要條件,即可註冊啟用機群 Workload Identity 聯盟。請按照「註冊叢集」一文中的叢集類型操作說明進行。

設定 IAM 工作負載身分集區

在本節中,您會在機群主機專案中建立新的 IAM workload identity pool,並授予機群服務代理程式新集區的存取權。

  1. 建立工作負載身分集區:

    gcloud iam workload-identity-pools create POOL_NAME \
        --location=global \
        --project=POOL_HOST_PROJECT_ID \
        --mode=TRUST_DOMAIN
    

    更改下列內容:

    • POOL_NAME:新工作負載身分集區的名稱。
    • POOL_HOST_PROJECT_ID:您要在其中建立自行管理的 workload identity pool 的專案 ID。您可以使用任何 Google Cloud 專案,包括機群主專案。
  2. 將新 workload identity 集區的 IAM Workload Identity Pool Admin 角色 (roles/iam.workloadIdentityPoolAdmin) 授予機群服務代理:

    gcloud iam workload-identity-pools add-iam-policy-binding POOL_NAME \
        --project=POOL_HOST_PROJECT_ID \
        --location=global \
        --member=serviceAccount:service-FLEET_HOST_PROJECT_NUMBER@gcp-sa-gkehub.iam.gserviceaccount.com \
        --role=roles/iam.workloadIdentityPoolAdmin \
        --condition=None
    

    FLEET_HOST_PROJECT_NUMBER 替換為車隊主專案的專案編號。

將自行管理的集區新增至機群設定

在本節中,您將透過機群 Workload Identity 聯盟啟用自行管理的集區,並將建立的集區新增至機群設定。本節也提供建立新團隊範圍和機群命名空間的說明。如果機群已設定團隊範圍和機群命名空間,請略過這些步驟。

  1. 在機群層級啟用機群 Workload Identity Federation:

    gcloud beta container fleet workload-identity enable \
      --project=FLEET_HOST_PROJECT_ID
    

    FLEET_HOST_PROJECT_ID 替換為車隊主機專案的專案 ID。

  2. 將自行管理的工作負載身分集區新增至 Fleet 設定:

    gcloud beta container fleet workload-identity scope-tenancy-pool set POOL_NAME
    

    POOL_NAME 替換為自行管理的 workload identity pool 名稱。這個值的語法如下:

    POOL_NAME.global.POOL_HOST_PROJECT_NUMBER.workload.id.goog
    
  3. 建立新的團隊範圍。如果您已有團隊範圍和機群命名空間,請跳至「驗證 workload identity pool 設定」一節。

    gcloud container fleet scopes create SCOPE_NAME
    

    SCOPE_NAME 替換為新團隊範圍的名稱。

  4. 在團隊範圍中建立新的機群命名空間:

    gcloud container fleet scopes namespaces create NAMESPACE_NAME \
        --scope=SCOPE_NAME
    

    NAMESPACE_NAME 替換為新車隊命名空間的名稱。

  5. 將機群中的叢集繫結至團隊範圍:

    gcloud container fleet memberships bindings create BINDING_NAME \
        --membership=FLEET_CLUSTER_NAME \
        --location=global \
        --scope=SCOPE_NAME
    

    更改下列內容:

    • BINDING_NAME:新成員綁定的名稱。
    • FLEET_CLUSTER_NAME:要繫結至團隊範圍的現有機群叢集名稱。

驗證工作負載身分集區設定

在本節中,您將確認自行管理的 workload identity pool 設定是否成功。

  1. 說明機群成員設定:

    gcloud container fleet memberships describe FLEET_CLUSTER_NAME \
        --location=global
    

    FLEET_CLUSTER_NAME 替換為機群中已繫結至任何團隊範圍的現有機群叢集名稱。

    輸出結果會與下列內容相似:

    authority:
    ...
      scopeTenancyIdentityProvider: https://gkehub.googleapis.com/projects/FLEET_HOST_PROJECT_ID/locations/global/memberships/FLEET_CLUSTER_NAME
      scopeTenancyWorkloadIdentityPool: POOL_NAME.global.FLEET_HOST_PROJECT_NUMBER.workload.id.goog
      workloadIdentityPool: FLEET_HOST_PROJECT_ID.svc.id.goog
    ...
    

    這項輸出內容應包含下列欄位:

    • scopeTenancyIdentityProvider:在團隊範圍內的機群命名空間中執行的工作負載身分識別提供者。這個值是叢集的資源 ID。
    • scopeTenancyWorkloadIdentityPool:工作負載身分集區,團隊範圍內 Fleet 命名空間中的工作負載會從這個集區取得 ID。這個值是您自行管理的工作負載身分集區,格式為 POOL_NAME.global.FLEET_HOST_PROJECT_NUMBER.workload.id.goog
    • workloadIdentityPool:機群主專案的 Google 管理 Workload Identity 集區名稱,機群中的所有其他工作負載預設都會從這個集區取得身分。
  2. 選用:檢查工作負載身分集區是否有名稱與機群命名空間相同的命名空間:

    gcloud iam workload-identity-pools namespaces list \
        --workload-identity-pool=POOL_NAME \
        --location=global
    

    輸出結果會與下列內容相似:

    ---
    description: Fleet namespace NAMESPACE_NAME
    name: projects/FLEET_HOST_PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_NAME/namespaces/NAMESPACE_NAME
    state: ACTIVE
    

機群現在可以使用自行管理的工作負載身分集區,為在機群命名空間中執行的工作負載取得身分。如要開始使用自行管理的集區,請設定特定叢集取得身分的方式,詳情請參閱下一節。

讓工作負載使用自行管理的集區做為身分

如要讓工作負載使用自行管理的集區,請使用 Kubernetes ConfigMap,在車隊成員叢集中設定特定車隊命名空間。這項以叢集和命名空間為單位的設定,可讓您進一步縮減授權範圍,從整個機群命名空間縮減至在特定叢集的特定機群命名空間中執行的工作負載。

  1. 連線至機群成員叢集:

    gcloud container clusters get-credentials FLEET_CLUSTER_NAME \
        --project=CLUSTER_PROJECT_ID \
        --location=CLUSTER_LOCATION
    

    更改下列內容:

    • FLEET_CLUSTER_NAME:已繫結至團隊範圍的機群成員叢集名稱。
    • CLUSTER_PROJECT_ID:叢集專案的專案 ID。
    • CLUSTER_LOCATION:叢集位置。
  2. 取得自行管理的工作負載身分集區完整名稱。稍後會用到。

    kubectl get membership membership -o json | jq -r ".spec.scope_tenancy_workload_identity_pool"
    

    輸出結果會與下列內容相似:

    POOL_NAME.global.FLEET_HOST_PROJECT_NUMBER.workload.id.goog
    
  3. 取得團隊範圍的識別資訊提供者名稱。稍後會需要用到。

    kubectl get membership membership -o json | jq -r ".spec.scope_tenancy_identity_provider"
    

    輸出結果會與下列內容相似:

    https://gkehub.googleapis.com/projects/FLEET_HOST_PROJECT_ID/locations/global/memberships/FLEET_CLUSTER_NAME
    
  4. 在文字編輯器中,將下列 ConfigMap 的 YAML 資訊清單儲存為 self-managed-pool.yaml

    kind: ConfigMap
    apiVersion: v1
    metadata:
      namespace: NAMESPACE_NAME
      name: google-application-credentials
    data:
      config: |
        {
          "type": "external_account",
          "audience": "identitynamespace:SELF_MANAGED_POOL_FULL_NAME:IDENTITY_PROVIDER",
          "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"
          }
        }
    

    更改下列內容:

    • NAMESPACE_NAME:機群命名空間的名稱。
    • SELF_MANAGED_POOL_FULL_NAME:這個部分中,上一個步驟輸出內容的自管 workload identity pool 完整名稱。例如:example-pool.global.1234567890.workload.id.goog
    • IDENTITY_PROVIDER:這個部分中,上一個步驟的輸出內容所列的 IDP 名稱。例如: https://gkehub.googleapis.com/projects/1234567890/locations/global/memberships/example-cluster.
  5. 在叢集中部署 ConfigMap:

    kubectl create -f self-managed-pool.yaml
    

部署 ConfigMap 會向 GKE 指出,該命名空間中的工作負載應使用自行管理的工作負載身分集區來取得身分。

將 IAM 角色授予主體

在本節中,您將在 Fleet 命名空間中建立 Kubernetes ServiceAccount,並將 IAM 角色授予該 ServiceAccount。使用這個 ServiceAccount 的 Pod 隨後就能存取您授予角色的 Google Cloud 資源。

  1. 在艦隊命名空間中建立 Kubernetes ServiceAccount:

    kubectl create serviceaccount SERVICEACCOUNT_NAME \
        --namespace=NAMESPACE_NAME
    

    更改下列內容:

    • SERVICEACCOUNT_NAME:新 ServiceAccount 的名稱。
    • NAMESPACE_NAME:機群命名空間的名稱。
  2. 將 IAM 角色授予 ServiceAccount。下列範例指令會將 bucket 的「Storage 物件檢視者」角色 (roles/storage.objectViewer) 授予 ServiceAccount:

    gcloud storage buckets add-iam-policy-binding gs://BUCKET_NAME \
        --member=principal://iam.googleapis.com/projects/FLEET_HOST_PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_NAME.global.FLEET_HOST_PROJECT_NUMBER.workload.id.goog/subject/ns/NAMESPACE_NAME/sa/SERVICEACCOUNT_NAME \
        --role=roles/storage.objectViewer \
        --condition=None
    

member 旗標包含您建立的新 ServiceAccount 的主體 ID。工作負載傳送至 Google CloudAPI 的要求會使用同盟存取權杖。這個同盟存取權權杖包含傳送要求的實體主體 ID。如果允許政策中授予目標資源角色的主體,與同盟存取權權杖中的主體相符,即可繼續進行驗證和授權。

部署使用自行管理集區的工作負載

您在機群命名空間中套用的 Kubernetes 資訊清單必須經過設定,才能從自行管理的集區取得身分。您部署的工作負載需要呼叫 Google Cloud API,因此應包含下列欄位:

  • metadata.namespace:機群命名空間的名稱。
  • spec.serviceAccountName:艦隊命名空間中 Kubernetes ServiceAccount 的名稱。
  • spec.containers.env:名為 GOOGLE_APPLICATION_CREDENTIALS 的環境變數,指出應用程式預設憑證 (ADC) 檔案的路徑。
  • spec.containers.volumeMounts:唯讀磁碟區,可讓容器使用 ServiceAccount 的不記名權杖。
  • spec.volumes:預計的磁碟區,可將 ServiceAccount 權杖掛接到 Pod 中。權杖的對象是自行管理的工作負載身分集區。包含 Fleet Workload Identity Federation 設定的 ConfigMap 是磁碟區的來源。

如要查看設定正確的資訊清單檔案範例,請參閱「從工作負載驗證驗證」一節。

驗證工作負載的驗證

本節提供選用操作說明,列出範例 Cloud Storage bucket 的內容,確認您是否正確設定自行管理的工作負載身分集區。您要建立值區,並將該值區的角色授予機群命名空間中的 ServiceAccount,然後部署 Pod,嘗試存取該值區。

  1. 建立 Cloud Storage bucket:

    gcloud storage buckets create gs://FLEET_HOST_PROJECT_ID-workload-id-bucket \
        --location=LOCATION \
        --project=FLEET_HOST_PROJECT_ID
    
  2. 將 Bucket 的 roles/storage.objectViewer 角色授予叢集命名空間中的 ServiceAccount:

    gcloud storage buckets add-iam-policy-binding gs://FLEET_HOST_PROJECT_ID-workload-id-bucket \
        --condition=None \
        --role=roles/storage.objectViewer \
        --member=principal://iam.googleapis.com/projects/FLEET_PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_NAME.global.FLEET_HOST_PROJECT_NUMBER.workload.id.goog/subject/ns/NAMESPACE_NAME/sa/SERVICEACCOUNT_NAME
    

    更改下列內容:

    • FLEET_HOST_PROJECT_NUMBER:機群主專案的專案編號。
    • POOL_NAME:自行管理的 workload identity pool 名稱。
    • NAMESPACE_NAME:要在其中執行 Pod 的 Fleet 命名空間名稱。
    • SERVICEACCOUNT_NAME:Pod 應使用的 Kubernetes ServiceAccount 名稱。
  3. 將下列資訊清單儲存為 pod-bucket-access.yaml

    apiVersion: v1
    kind: Pod
    metadata:
      name: bucket-access-pod
      namespace:  NAMESPACE_NAME
    spec:
      serviceAccountName: SERVICEACCOUNT_NAME
      containers:
      - name: sample-container
        image: google/cloud-sdk:slim
        command: ["sleep","infinity"]
        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: POOL_NAME.global.FLEET_HOST_PROJECT_NUMBER.workload.id.goog
              expirationSeconds: 172800
          - configMap:
              name: my-cloudsdk-config
              optional: false
              items:
              - key: "config"
                path: "google-application-credentials.json"
    

    更改下列內容:

    • NAMESPACE_NAME:要在其中執行 Pod 的 Fleet 命名空間名稱。
    • SERVICEACCOUNT_NAME:Pod 應使用的 Kubernetes ServiceAccount 名稱。
    • POOL_NAME:自行管理的 workload identity pool 名稱。
    • FLEET_HOST_PROJECT_NUMBER:機群主專案的專案編號。
  4. 在叢集中部署 Pod:

    kubectl apply -f pod-bucket-access.yaml
    
  5. 在 Pod 中開啟殼層工作階段:

    kubectl exec -it bucket-access-pod -n NAMESPACE_NAME -- /bin/bash
    
  6. 嘗試列出值區中的物件:

    curl -X GET -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
        "https://storage.googleapis.com/storage/v1/b/FLEET_HOST_PROJECT_ID-workload-id-bucket/o"
    

    輸出內容如下:

    {
      "kind": "storage#objects"
    }
    

您也可以選擇驗證不同機群成員叢集中類似的命名空間和 ServiceAccount,是否無法聲明相同身分。在採用機群 Workload Identity 聯盟,但沒有機群命名空間或自我管理集區設定的叢集中,請完成下列步驟:

  1. 建立新的 Kubernetes 命名空間,名稱與您設定自行管理工作負載身分識別集區的機群命名空間相同。
  2. 建立新的 Kubernetes ServiceAccount,名稱與您在先前章節中授予 IAM 角色的 ServiceAccount 相同。
  3. 部署使用相同 ServiceAccount 和命名空間的 Pod,但 spec.volumes.projected.sources.serviceAccountToken 欄位指定 Google 管理的工作負載身分識別集區。這個集區的語法如下:

    FLEET_HOST_PROJECT_ID.svc.id.goog
    
  4. 嘗試從 Pod 的 Shell 工作階段存取 Cloud Storage bucket。

輸出內容應為 401: Unauthorized 錯誤,因為使用 Google 代管工作負載身分集區的 Pod 主體 ID,與使用自行管理集區的 Pod 主體 ID 不同。

後續步驟