在 GKE 中使用代理身分進行驗證

具有代理程式身分的 Google Kubernetes Engine (GKE) 代理程式,可以使用該身分向 API 和外部工具與服務進行驗證。 Google Cloud 代理程式可以使用自己的身分,或代表使用者採取行動。本文說明代理程式應用程式開發人員如何設定應用程式,向各種資源進行驗證。您應該已熟悉如何為 GKE 代理要求代理身分。

視代理程式需要存取的資源而定,平台管理員可能需要設定授權管理員憑證保險箱,才能執行其他工作流程。舉例來說,如要讓代理程式代表使用者向 GitHub 進行驗證,驗證管理工具中的 3 腿 OAuth 驗證供應商必須處理使用者登入、授權和重新導向作業。開發人員會修改代理程式,呼叫正確的驗證提供者,並處理使用者繼續對話的要求。

限制

  • 請參閱「代理程式身分限制」。
  • 您只能使用 Google 驗證程式庫,取得 Python 的繫結存取權和 ID 權杖。驗證程式庫可能無法取得其他語言的繫結權杖。如果使用其他語言,請將 GOOGLE_API_ENABLE_RUNTIME_BOUND_TOKEN 環境變數設為 false,切換為未繫結的權杖。

事前準備

開始之前,請務必先完成下列工作:

  • 啟用 Google Kubernetes Engine API。
  • 啟用 Google Kubernetes Engine API
  • 如要使用 Google Cloud CLI 執行這項工作,請安裝並初始化 gcloud CLI。如果您先前已安裝 gcloud CLI,請執行 gcloud components update 指令,取得最新版本。較舊的 gcloud CLI 版本可能不支援執行本文件中的指令。

必要的角色

如要取得在 GKE 叢集中設定已部署代理程式所需的權限,請要求管理員授予您專案的 Kubernetes Engine 開發人員 (roles/container.developer) IAM 角色。如要進一步瞭解如何授予角色,請參閱「管理專案、資料夾和組織的存取權」。

您或許也能透過自訂角色或其他預先定義的角色,取得必要權限。

向 Google Cloud API 驗證

如要以代理程式的身分向 Google Cloud API 進行驗證,代理程式可以使用節點上中繼資料伺服器的代理程式身分存取權杖。您可能需要對程式碼進行的變更,取決於您呼叫 API 的方式,如下所示。 Google Cloud

使用 Cloud 用戶端程式庫

如果您使用的 Cloud 用戶端程式庫版本包含 google-auth 程式庫 2.61.0 以上版本,應用程式預設憑證 (ADC) 會自動取得代理程式身分存取權杖。您不需要對程式碼進行額外變更。如果您透過設定 iam.gke.io/inject-podcertificates: "true" 註解,為 Pod 啟用憑證插入功能,存取權杖預設會繫結至 X.509 憑證,除非您停用繫結權杖。

使用 Cloud 用戶端程式庫時,如要取得未繫結的存取權杖,請執行下列其中一項操作:

  • 在 Pod 中啟用憑證插入功能,並將 GOOGLE_API_ENABLE_RUNTIME_BOUND_TOKEN 環境變數設為 false。
  • 請勿在 Pod 中啟用憑證插入功能。

直接呼叫 Google Cloud API 端點

如果您未使用 Cloud 用戶端程式庫與服務互動,可以透過下列方式,使用代理程式的身分向 Google Cloud API 進行驗證:

  1. 從節點上的中繼資料伺服器取得存取權杖。你可以使用下列任一方法取得權杖:

    • 繫結存取權杖:使用 google-auth Python 程式庫,該程式庫會探索 Pod 的 X.509 憑證,並預設自動取得繫結存取權杖。如要使用其他程式設計語言,請使用未繫結的權杖。

    • 未繫結的存取權杖:如果 Pod 沒有代理身分憑證套件,請使用您程式設計語言的 Google 驗證程式庫。驗證程式庫會自動取得未繫結的存取權杖,並為您重新整理即將過期的權杖。對於 Pod 中具有憑證組合的 Python 應用程式,請在 Pod 規格中將 GOOGLE_API_ENABLE_RUNTIME_BOUND_TOKEN 環境變數設為 false,如下列範例所示:

      # Multiple lines are omitted here.
      spec:
        containers:
        - name: example-agent
          image: example-image
          env:
          - name: GOOGLE_API_ENABLE_RUNTIME_BOUND_TOKEN
            value: "false"
      # Multiple lines are omitted here.
      

      這個環境變數可防止程式庫取得繫結的存取權杖和 ID 權杖。

  2. 如要使用繫結存取權杖,請將要求傳送至 API 的 mTLS 端點,並在 HTTP 傳輸中加入代理程式身分 X.509 憑證鏈結。如果您使用 Python 適用的 Google 驗證程式庫,該程式庫會為您處理 HTTP 傳輸設定。

以下範例說明如何使用 Python 適用的 Google 驗證程式庫,取得繫結存取權杖,並向 Cloud Storage mTLS 端點提出要求:

import google.auth
from google.auth.transport.requests import AuthorizedSession


def call_storage_api_mtls(bucket_name: str) -> None:
    # Discover the Pod's X.509 certificate chain by using the auth library
    credentials, project = google.auth.default(
        scopes=["https://www.googleapis.com/auth/cloud-platform"]
    )
    # Configure the mTLS session by using the Pod's certificate chain
    session = AuthorizedSession(credentials)
    session.configure_mtls_channel()
    # Call the Google Cloud mTLS endpoint
    mtls_url = f"https://storage.mtls.googleapis.com/storage/v1/b/{bucket_name}/o"
    response = session.get(mtls_url)
    response.raise_for_status()
    print(response.json())

驗證外部工具和服務

如要向外部工具和服務進行驗證,您可以設定代理,從 Agent Identity 驗證管理工具取得必要憑證。平台管理員會在驗證管理工具中設定各種驗證供應商,每個供應商都會管理特定的驗證工作流程和憑證。您修改應用程式程式碼,呼叫特定驗證提供者,並視驗證工作流程而定,處理使用者同意聲明和對話續傳。您對代理進行的具體變更取決於您需要存取的內容,如下所示:

驗證管理員會處理相應的驗證工作流程,並授予代理加密憑證的存取權,然後將憑證納入對外部服務的要求。如要進一步瞭解平台管理員必須執行的操作,才能設定這些驗證提供者,並授予代理程式身分存取權,請參閱「代理程式的驗證工作流程」。

向其他代理驗證

在多代理架構中,代理通常會直接叫用同層級代理或下游服務,藉此進行協作。您可以使用身分識別權杖,在代理工作負載之間建立直接通訊。您可以從 GKE 中繼資料伺服器取得繫結或未繫結的 ID 權杖,並使用該權杖直接向其他代理程式進行驗證。

如要取得 ID 權杖並在 HTTP 要求中使用該權杖,請使用 Python 適用的 Google 驗證程式庫。程式庫會自動處理憑證探索和 ID 權杖取得作業。如果您使用其他程式設計語言,Google 驗證程式庫可能無法取得繫結的 ID 權杖。請改用未繫結的 ID 權杖。

取得 ID 權杖

如要在代理程式碼中要求 ID 權杖,請使用您程式設計語言的 Google 驗證程式庫。您可以使用程式庫要求繫結或未繫結的 ID 權杖,如下所示:

  • 繫結 ID 權杖:使用 iam.gke.io/inject-podcertificates: "true" 註解,為 Pod 啟用憑證插入功能。Python 的驗證程式庫會自動向 GKE 中繼資料伺服器要求與憑證綁定的 ID 權杖。在透過 mTLS 執行的代理之間進行驗證時,請使用繫結 ID 權杖。 Google Cloud
  • 未繫結的 ID 權杖:

    • 為 Pod 啟用憑證插入功能,然後執行下列其中一項操作:
      • 在應用程式程式碼的 id_token.fetch_id_token 函式中,將 bind_id_token 引數設為 False 值。這個引數會導致驗證程式庫要求未繫結的 ID 權杖。存取權杖要求不受影響。
      • 在 Pod 規格中,將 GOOGLE_API_ENABLE_RUNTIME_BOUND_TOKEN 環境變數設為 false 值。這個環境變數可防止程式庫要求繫結存取權杖和 ID 權杖。
    • 請勿為 Pod 啟用憑證插入功能。由於 Pod 中沒有憑證組合,驗證程式庫會取得未繫結的 ID 權杖。

    透過非 mTLS 連線向 Google Cloud API、外部服務或其他代理程式進行驗證時,請使用未繫結的 ID 權杖。

以下範例說明如何為已啟用憑證插入功能的代理程式,要求繫結或未繫結的 ID 權杖:

  • 要求繫結 ID 權杖:

    import google.auth.transport.requests
    from google.oauth2 import id_token
    
    # Application Default Credentials automatically requests a certificate-bound
    # ID token.
    def get_bound_id_token(target_audience: str) -> str:
        auth_req = google.auth.transport.requests.Request()
        return id_token.fetch_id_token(auth_req, audience=target_audience)
    

    繫結的身分識別權杖會在 cnf.x5t#S256 參數中,加入 Pod X.509 憑證鏈結的 SHA-256 憑證指紋。

  • 要求未繫結的 ID 權杖:

    import google.auth.transport.requests
    from google.oauth2 import id_token
    
    def get_unbound_id_token(target_audience: str) -> str:
        auth_req = google.auth.transport.requests.Request()
        return id_token.fetch_id_token(
            auth_req,
            audience=target_audience,
            # Always get an unbound ID token, even if the Pod has a credential
            # bundle.
            bind_id_token=False,
        )
    

在對其他代理程式的要求中使用 ID 權杖

取得代理的 ID 權杖後,即可使用該權杖直接向另一個代理驗證身分。驗證連線的方式取決於您是否使用繫結 ID 權杖,如下所示:

  • 如為繫結的 ID 權杖,請與接收代理程式建立 mTLS 連線,並使用 Pod 中 /var/run/secrets/workload-spiffe-credentials/ 目錄的下列憑證驗證連線:
    • x509.credential-bundle.private-key.pem 檔案中的代理程式身分憑證套件,內含 Pod 的葉片憑證鏈結。
    • TRUST_DOMAIN.spiffe-trust-bundle.pem 檔案中的叢集信任組合。這個檔案包含接收代理程式的根 CA 憑證,用於在 mTLS 握手期間驗證接收代理程式的憑證鏈結。撥號和接聽電話的服務專員必須位於同一個服務專員身分集區。
  • 如果是未繫結的 ID 權杖,請與接收代理程式建立非 mTLS 連線。

以下範例說明如何使用繫結或未繫結的 ID 權杖,將要求傳送至其他代理程式:

  • 繫結的 ID 權杖:在傳送至接收代理程式 mTLS 端點的要求 Authorization: Bearer 標頭中,加入繫結的 ID 權杖。使用 Pod 的 X.509 憑證和私密金鑰驗證 TLS 連線:

    import ssl
    import urllib3
    
    BUNDLE_PATH = "/var/run/secrets/workload-spiffe-credentials/x509.credential-bundle.private-key.pem"
    TRUST_BUNDLE_PATH = "/var/run/secrets/workload-spiffe-credentials/TRUST_DOMAIN.spiffe-trust-bundle.pem"
    
    def call_peer_agent_bound_mtls(target_mtls_url: str, target_audience: str) -> None:
    
        # Configure the mTLS context by using the certificate chain and trust
        # bundle from the Pod.
        ctx = ssl.create_default_context(cafile=TRUST_BUNDLE_PATH)
        ctx.load_cert_chain(BUNDLE_PATH)
        http = urllib3.PoolManager(ssl_context=ctx, assert_hostname=False)
    
        # Call a peer agent's mTLS endpoint by using the bound ID token and Pod
        # certificate chain.
        bound_id_token = get_bound_id_token(target_audience)
        response = http.request(
            "POST",
            target_mtls_url,
            headers={"Authorization": f"Bearer {bound_id_token}"},
            json={"task": "analyze_data"},
            timeout=10,
        )
        print(response.json())
    

    將 TRUST_DOMAIN 替換為代理程式身分集區的信任網域。

  • 未繫結的 ID 權杖:在向對等代理提出的要求中,將權杖加入 Authorization: Bearer 標頭:

    import requests
    
    def call_peer_agent_unbound(target_url: str, target_audience: str) -> None:
        unbound_id_token = get_unbound_id_token(target_audience)
        # Send the request by using a standard TLS connection or plain HTTP.
        response = requests.post(
            target_url,
            headers={"Authorization": f"Bearer {unbound_id_token}"},
            json={"task": "analyze_data"},
            timeout=10,
        )
        response.raise_for_status()
        print(response.json())
    

在接收代理程式中驗證要求

在接收代理程式中,執行下列步驟,驗證傳入要求中的 ID 權杖。您可以透過 Tink 等密碼編譯程式庫執行這些驗證步驟,不必編寫自訂程式碼。

  1. 從要求 Authorization: Bearer 標頭中擷取 ID 權杖。
  2. 確認 ID 權杖中的 iss (簽發者) 聲明是呼叫代理程式的代理程式身分集區。視呼叫代理程式是否位於組織的專案中,簽發者為下列其中一項:
    • 機構中的專案: https://sts.googleapis.com/v1/organizations/ORGANIZATION_ID/locations/global/workloadIdentityPools/agents.global.org-ORGANIZATION_ID.system.id.goog,其中 ORGANIZATION_ID 是包含呼叫代理程式專案的機構 ID。
    • 不屬於任何機構的專案: https://sts.googleapis.com/v1/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/agents.global.proj-PROJECT_NUMBER.system.id.goog, 其中 PROJECT_NUMBER 是呼叫代理程式 GKE 叢集的專案編號。
  3. 找出核發者的 JSON Web Key Set (JWKS) URI,並快取公開 JSON Web Key (JWKS)。JWKS 的端點格式為 ISSUER_URL/openid/jwks,其中 ISSUER_URL 是簽發者網址。
  4. 使用 ID 權杖的 JOSE 標頭中的下列資訊,驗證權杖簽章:
    • 與 kid 標頭參數相符的公開 JWK。
    • 與 alg 標頭參數相符的加密演算法,例如 RS256。
  5. 確認 cnf.x5t#S256 參數中的 SHA-256 憑證指紋,與呼叫端代理程式用來驗證 mTLS 連線的 X.509 憑證指紋相符。
  6. 驗證 ID 權杖中的下列聲明:
    • exp 聲明中的到期時間設在未來。
    • aud 聲明中的目標對象是接收代理程式。
  7. 根據權杖 sub (主體) 宣告中的 SPIFFE ID 授權要求。

後續步驟