設定 Workload Identity Federation 的憑證式存取權

本文說明如何使用 X.509 憑證,為 Workload Identity Federation 設定憑證式存取權。

憑證型存取權會使用相互傳輸層安全標準 (mTLS) 在 TLS 握手期間驗證用戶端和伺服器。在這個程序中,mTLS 繫結會根據傳輸環境納入政策,並使用 TLS 工作階段中用戶端憑證的狀態來做出授權決策。

如果是 X.509 工作負載身分聯盟,mTLS 繫結可確保整個驗證流程安全地繫結至受信任的工作負載。由於驗證程序會繫結至特定信任端點,因此可降低憑證遭竊的風險。

Workload Identity Federation 設定總覽:以憑證為基礎的存取權

以下概略說明如何設定 Workload Identity Federation 的憑證式存取權:

  1. 設定 X.509 憑證的信任錨點,建立工作負載身分聯盟。

  2. 建立憑證式存取的存取層級。

  3. 將存取層級新增至強制執行 mTLS 繫結的情境感知存取權政策。

事前準備

請確認您符合下列必要條件:

  • 最新版 Google Cloud CLI

    如要更新至最新版 Google Cloud CLI,請執行下列指令:

    gcloud components update
    

    如需安裝 Google Cloud CLI,請參閱「安裝 Google Cloud CLI」。

  • 使用 X.509 憑證信任錨點的 Workload Identity 聯盟設定

  • 如要使用這項功能,請填寫下列表單,將您加入許可清單:許可清單要求表單。 加入許可清單後,我們會與你聯絡。

建立憑證的存取層級

  1. 建立 mTLS 存取層級。判斷資源存取權時,mTLS 存取層級會驗證憑證。

    主控台

    在 Access Context Manager 中建立自訂存取層級,然後在 CEL 運算式欄位中輸入下列運算式: request.auth.matchesMtlsTokens(origin) == true

    gcloud

    如要建立自訂存取層級,請執行下列指令:

       gcloud access-context-manager levels create ACCESS_LEVEL_NAME 
    --title=TITLE
    --custom-level-spec=FILE
    --description=DESCRIPTION
    --policy=POLICY_NAME

    更改下列內容:

    • ACCESS_LEVEL_NAME:存取層級的名稱。
    • TITLE:存取層級的標題。
    • FILE:包含下列內容的 YAML 檔案:request.auth.matchesMtlsTokens(origin) == true
    • DESCRIPTION:存取層級的說明。
    • POLICY_NAME:存取權政策的名稱。
  2. 將您建立的存取層級匯出至環境變數。後續步驟會用到這個變數。

      export ACCESS_LEVEL_ID=ACCESS_LEVEL_ID
      

    ACCESS_LEVEL_ID 替換為存取層級名稱,例如 accessPolicies/12345/accessLevels/acl_1

為工作負載身分集區建立情境感知存取權繫結

  1. 設定下列環境變數。

    export ORG_ID=ORG_ID
    export CALLER_PROJECT_ID=CALLER_PROJECT_ID
    export FEDERATED_PRINCIPAL=FEDERATED_PRINCIPAL
    

    更改下列內容:

    • ORG_ID:貴機構的 ID。
    • CALLER_PROJECT_ID:用於呼叫 API 的專案 ID。
    • FEDERATED_PRINCIPAL:工作負載身分識別集區中身分主體的名稱,必須符合情境感知存取權政策。你可以使用下列任一選項:

      格式為 - principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/subject/SUBJECT_ATTRIBUTE_VALUE 的單一身分

      集區中的所有身分,格式為 - principalSet://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/*

    gcloud

    gcloud alpha access-context-manager cloud-bindings create \
    --organization=ORG_ID \
    --federated-principal=FEDERATED_PRINCIPAL \
    --level=ACCESS_LEVEL_ID
    --dry-run-level=DRY_RUN_ACCESS_LEVEL_ID
    

    更改下列內容:

    • ACCESS_LEVEL_ID:存取層級名稱。
    • DRY_RUN_ACCESS_LEVEL_ID:模擬測試存取層級名稱。建議您先啟用模擬執行政策繫結,瞭解對現有流量的潛在影響。

    curl

    1. 建立含有情境感知存取權繫結的 JSON 檔案。

      即使欄位重複,您在要求中也只能提供一個存取層級。您可以使用下列類型的同盟主體:

      • 單一身分: principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/subject/SUBJECT_ATTRIBUTE_VALUE
      • 集區中的所有身分: principalSet://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/*
      echo { \
        \"principal\": { \
          \"federatedPrincipal\": \"${FEDERATED_PRINCIPAL:?}\" \
        },\
        \"accessLevels\": [\"${ACCESS_LEVEL_ID:?}\"] \
      } \
      >> request.json
      
    2. 請使用 curl 傳送下列 HTTP 要求。

      curl -H "X-Goog-User-Project: ${CALLER_PROJECT_ID:?}" -X POST \
         -H "Authorization: Bearer $(gcloud auth print-access-token)" \
         -H "Content-Type: application/json; charset=utf-8" \
         -d @request.json \
       "https://accesscontextmanager.googleapis.com/v1alpha/organizations/${ORG_ID:?}/gcpUserAccessBindings"
      

使用 Google Cloud 用戶端程式庫授權

如要使用Google Cloud 用戶端程式庫授權 Workforce Identity Federation 工作負載,請完成下列步驟。

  1. 建立為員工身分聯盟驗證設定的應用程式預設憑證 (ADC) 檔案。

    gcloud iam workload-identity-pools create-cred-config IDENTITY_POOL_ID \
    --credential-cert-path WORKLOAD_CERTIFICATE_PATH \
    --credential-cert-private-key-path WORKLOAD_KEY_PATH \
    --output-file ADC_FILE_OUTPUT_PATH
    

    更改下列內容:

    • IDENTITY_POOL_ID:工作負載身分集區的 ID。
    • WORKLOAD_CERTIFICATE_PATH:工作負載憑證檔案的路徑。
    • WORKLOAD_KEY_PATH:工作負載私密金鑰檔案的路徑。
    • ADC_FILE_OUTPUT_PATH:ADC 檔案的輸出路徑。

    這個指令也會在 gcloud CLI 預設設定目錄中產生憑證設定檔。憑證設定檔支援初始驗證,並為後續對 Google Cloud 資源的要求建立 mTLS 交握。

  2. 設定環境變數,指向 ADC 檔案。這樣 Google 用戶端程式庫就能探索您的憑證。

    export GOOGLE_APPLICATION_CREDENTIALS=${application_default_credentials.json}
    

    如果您在產生 ADC 檔案時省略 --output-file 引數,則可略過這個步驟。如果省略引數,系統會從 gcloud CLI 預設設定目錄建立及讀取 ADC 檔案。

  3. 如要建立及測試對 Google Cloud API 的存取權,請完成下列步驟。您可以使用 Go 或 Python。

    Go

    1. 請使用下列範例建立 Go 檔案,例如 golang_test.go

      package golang_test
      
      import (
           "io"
           "log"
           "testing"
      
           "cloud.google.com/go/auth/credentials"
           "cloud.google.com/go/auth/httptransport"
      )
      
      func TestGoExample(t *testing.T) {
      
           scopes := []string{
                   "https://www.googleapis.com/auth/pubsub", // Scope for Pub/Sub access
                   // Add other scopes as needed
           }
      
           dopts := credentials.DetectOptions{
                   Scopes: scopes,
           }
      
           // Create httptransport.Options with the scopes
           opts := &httptransport.Options{
                   DetectOpts: &dopts,
           }
           hc, err := httptransport.NewClient(opts)
           if err != nil {
                   t.Fatalf("NewHTTPClient: %v", err)
           }
      
           resp, err := hc.Get("https://pubsub.mtls.googleapis.com/v1/projects/PROJECT_ID/topics")
           if err != nil {
                   t.Fatalf("Get: %v", err)
           }
           t.Logf("Status: %s", resp.Status)
      
           t.Cleanup(func() {
                  resp.Body.Close()
           })
      
           b, err := io.ReadAll(resp.Body)
           if err != nil {
                  t.Fatal(err)
           }
           log.Println(string(b))
      }
      

      PROJECT_ID 替換為您的 gcloud CLI 專案 ID。

    2. 如要在 Compute Engine VM 上執行測試,請使用下列指令。

    go mod init example.com
    go mod tidy
    go test -v golang_test.go --count=1
    

    Python

    1. 請使用下列範例建立測試檔案,例如 python_test.py

      import google.auth
      import google.auth.transport.requests
      import requests
      
      def test_go_example():
      # Define the required scopes for your application
      scopes = [
         "https://www.googleapis.com/auth/pubsub",  # Scope for Pub/Sub access
         # Add other scopes as needed
      ]
      
      # Obtain Application Default Credentials (ADC) with the specified scopes
      credentials, _ = google.auth.default(scopes=scopes)
      
      # Create an authorized HTTP session using the ADC credentials
      authed_session = google.auth.transport.requests.AuthorizedSession(credentials)
      
      try:
      # Make a GET request to the Pub/Sub API endpoint
      response = authed_session.get(
          "https://pubsub.mtls.googleapis.com/v1/projects/PROJECT_ID/topics"
      )
      
      # Check if the request was successful
      response.raise_for_status()  # Raise an exception for error statuses
      
      # Log the response status and content
      print(f"Status: {response.status_code}")
      print(response.text)
      
      except requests.exceptions.RequestException as e:
      print(f"Error making the request: {e}")
      
      if __name__ == "__main__":
      test_go_example()
      

      PROJECT_ID 替換為您的 gcloud CLI 專案 ID。

    2. 如要在 Compute Engine VM 上執行測試,請完成下列步驟。

      1. 設定 Python 虛擬環境。
      2. 安裝必要的程式庫。

        pip install google-auth google-auth-httplib2 requests
        
      3. 執行測試:

        python3 python_test.py
        

使用純文字 HTTP 要求授權

如要使用純 HTTP 要求授權 Workforce Identity Federation 工作負載,請完成下列步驟。

  1. 透過標準 mTLS 交握程序,從 Google Cloud 安全權杖服務取得與憑證綁定的存取權杖

  2. 使用從 Security Token Service 取得的存取權杖呼叫 Google Cloud 服務。這個範例會查詢 Cloud Storage。

    $ curl --key ${workload_key.pem} --cert ${workload_cert.pem} -X GET 'https://storage.mtls.googleapis.com/{replace_with_your_resources}' -H "Authorization: Bearer $ACCESS_TOKEN"
    
  3. mTLS 繫結會強制使用 mTLS。執行下列指令,確認非 mTLS 連線會因未經授權而失敗。

    $ curl -X GET 'https://storage.googleapis.com/{replace_with_your_resources}' -H "Authorization: Bearer $ACCESS_TOKEN"
    

列出政策繫結

如要列出 Workload Identity 聯盟的政策繫結,請執行下列指令。

gcloud

下列指令會列出指定機構內的特定繫結,並篩選適用於聯盟主體的繫結。

gcloud alpha access-context-manager cloud-bindings list \
--organization=ORG_ID \
--filter='principal:federatedPrincipal'

curl

curl -H "X-Goog-User-Project: ${CALLER_PROJECT_ID:?}" -X GET \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
"https://accesscontextmanager.googleapis.com/v1alpha/organizations/${ORG_ID:?}/gcpUserAccessBindings?filter=principal%3Afederated_principal"

更新政策繫結

如要更新政策繫結,請將新的存取層級新增至 JSON 檔案,然後執行下列指令。

gcloud

gcloud alpha access-context-manager cloud-bindings update \
--binding=BINDING_ID \
--level=NEW_ACCESS_LEVEL_ID

curl

curl -H "X-Goog-User-Project: ${CALLER_PROJECT_ID:?}" -X PATCH \
 -H "Authorization: Bearer $(gcloud auth print-access-token)" \
 -H "Content-Type: application/json; charset=utf-8" \
 -d @request.json \
"https://accesscontextmanager.googleapis.com/v1alpha/organizations/${ORG_ID:?}/gcpUserAccessBindings/${BINDING_ID:?}?updateMask=access_levels"

刪除政策繫結

如要刪除政策繫結,請執行下列指令。

gcloud

gcloud alpha access-context-manager cloud-bindings delete \
--binding=BINDING_ID

curl

curl -H "X-Goog-User-Project: ${CALLER_PROJECT_ID:?}" -X DELETE \
   -H "Authorization: Bearer $(gcloud auth print-access-token)" \
"https://accesscontextmanager.googleapis.com/v1alpha/organizations/${ORG_ID:?}/gcpUserAccessBindings/${BINDING_ID:?}"

疑難排解

以下列出幾個常見問題和建議解決方法:

  • 錯誤:403 Forbidden, user does not have permission.

    動作:檢查 IAM 政策,確認工作負載身分集區有權存取 Google Cloud 資源。

  • 錯誤:Unauthorized_client: Could not obtain a value for google.subject from the given credential.

    動作:後端無法根據屬性對應,從用戶端憑證中擷取 google.subject 的值。檢查用戶端憑證,確認您用來對應的欄位有值。

  • 啟用情境感知存取權後,如果遇到非預期的存取遭拒情況,可以使用下列指令移除情境感知存取權繫結,快速解除封鎖流量:

    gcloud alpha access-context-manager cloud-bindings delete
    

    存取權恢復後,請查看稽核記錄,判斷要求遭拒的原因。