整合 Cloud Run 和 Workload Identity 聯盟


本教學課程說明如何使用工作負載身分聯盟,驗證在 Google Cloud 外部執行的工作負載,讓這些工作負載存取 Cloud Run 代管的微服務。本教學課程適用於想將 Workload Identity Federation 與現有身分提供者 (IdP) 整合的系統管理員。Workload Identity 聯盟可讓您將外部工作負載連線至 Google Cloud中執行的工作負載。Cloud Run 可讓您執行無狀態容器化微服務。

本教學課程提供相關操作說明,說明如何將 Jenkins 設定為外部工作負載、Keycloak 設定為 IdP、Cloud Run,以及 Workload Identity Federation。完成本教學課程後,您會瞭解如何使用 OpenID Connect 驗證,透過 Workload Identity Federation 驗證 Jenkins 應用程式。 Google Cloud

使用 Workload Identity 聯盟驗證外部工作負載

Workload Identity 聯盟可讓您驗證 Google Cloud 外部的工作負載,無須使用靜態服務帳戶金鑰。任何需要使用Google Cloud 中服務的外部工作負載,都能從這項功能獲益。

有了 Workload Identity 聯盟,即可透過 IdP 直接向Google Cloud驗證身分。如要進行驗證,請使用 OpenID Connect。Cloud Run 會接受來自 IdP 的 OpenID Connect 權杖,用於驗證。

使用 Workload Identity 聯盟時的驗證程序如下:

  1. 驗證 (AUTHN) 程式庫會將 JSON Web Token (JWT) 要求傳送至 IdP。
  2. 您的 IdP 會簽署 JSON Web Token (JWT)。AUTHN 程式庫會從變數讀取這項資料。
  3. 程式庫會將包含已簽署權杖的 POST 指令傳送至安全權杖服務
  4. 安全性權杖服務會查看您設定的 workload identity pool 提供者,建立信任關係並驗證憑證上的身分。
  5. 安全性權杖服務會傳回同盟存取權杖
  6. 程式庫會將同盟存取權杖傳送至 IAM。
  7. 身分與存取權管理服務會將聯合存取權杖換成 ID 權杖。詳情請參閱「建立 OpenID Connect (OIDC) ID 權杖」。
  8. 程式庫會將 ID 權杖提供給 Jenkins。
  9. Jenkins 會使用這個權杖向 Cloud Run 進行驗證。

下圖說明驗證流程:

驗證流程。

目標

  • 將 Jenkins 設定為外部工作負載。
  • Keycloak 設定為與 OpenID Connect 相容的 IdP。
  • 將 Jenkins 連結至 Keycloak。
  • 安裝 Cloud 用戶端程式庫,從 Keycloak 取得 JWT 權杖 Google Cloud。
  • 連線 Google Cloud 至 Keycloak 和 Jenkins。
  • 從 Keycloak 取得通過驗證的使用者的 JWT。

本教學課程使用 Keycloak,但您可以改用任何支援 OpenID Connect 的識別資訊提供者,例如 GitLab、Okta 或 OneLogin。

費用

在本文件中,您會使用 Google Cloud的下列計費元件:

如要根據預測用量估算費用,請使用 Pricing Calculator

初次使用 Google Cloud 的使用者可能符合免費試用資格。

完成本文所述工作後,您可以刪除已建立的資源,避免繼續計費。詳情請參閱清除所用資源一節。

事前準備

  1. In the Google Cloud console, go to the project selector page.

    Go to project selector

  2. Select or create a Google Cloud project.

  3. Verify that billing is enabled for your Google Cloud project.

  4. 在 Cloud Run 上設定微服務。詳情請參閱「 快速入門導覽課程:將容器部署至 Cloud Run」。

設定 Jenkins

在非Google Cloud 環境中完成這些工作,例如地端環境或其他雲端。

如果您已有支援 OpenID Connect 的身分提供者和外部工作負載,可以略過這個步驟,直接前往安裝 Cloud 用戶端程式庫

如要模擬外部工作負載,可以使用已安裝 Jenkins 的 VM。您可以將 Jenkins 做為 Docker 映像檔執行,也可以直接安裝到伺服器。下列步驟說明如何直接在伺服器上安裝。

  1. 在您選擇的 VM 上開啟指令列。
  2. 安裝 Java:

    $ sudo apt update
    $ sudo apt install openjdk-11-jre
    $ java -version
    
  3. 安裝 Jenkins:

    curl -fsSL https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key | sudo tee \
    /usr/share/keyrings/jenkins-keyring.asc > /dev/null
    echo deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc] \
    https://pkg.jenkins.io/debian-stable binary/ | sudo tee \
    /etc/apt/sources.list.d/jenkins.list > /dev/null
    sudo apt-get update
    sudo apt-get install jenkins
    
  4. 確認是否能透過通訊埠 8080 存取 Jenkins 伺服器。如果您使用的 VM 位於防火牆後方,請確認已開啟適當的通訊埠。

  5. 取得管理員密碼並設定 Jenkins。如需操作說明,請參閱安裝後設定精靈

  6. 如要設定 SSL,請完成下列動作:

    1. 如果您有網域供應商,可以透過他們的憑證授權單位 (CA) 要求簽署憑證。或者,您也可以從 zerossl.com 取得 90 天的免費簽署憑證。
    2. 下載憑證 ZIP 檔案,並將檔案轉移至執行 Jenkins 的伺服器:

      scp -i CERTFILE.pem -r CERTFILE.zip VM_FQDN:/home/USERNAME
      

      更改下列內容:

      • CERTFILE,其中包含公開金鑰的憑證檔案名稱。
      • VM_FQDN 改為伺服器的 FQDN (位於 Google Cloud外部)。
      • USERNAME 改為您的使用者名稱。
    3. 重新命名檔案,並產生 Jenkins 可用的 .pkcs12 檔案:

      openssl rsa -in KEYFILE.com.key -out KEYFILE.com.key

      KEYFILE 改為憑證檔案名稱。

  7. 更新 /etc/sysconfig/jenkins 檔案:

    1. 在文字編輯器中開啟檔案:

      vi /etc/sysconfig/jenkins
      
    2. JENKINS_PORT 設為 -1

    3. JENKINS_HTTPS_PORT 設為 8443

    4. 在檔案底部新增下列引數:

      JENKINS_ARGS="--httpsCertificate=/var/lib/jenkins/.ssl/CERTFILE.crt --httpsPrivateKeys=/var/lib/jenkins/.ssl/KEYFILE.pkcs1.key"

      更改下列內容:

      • CERTFILE,並使用 .crt 格式的憑證檔案名稱。
      • KEYFILE 替換為 PKCS 金鑰的檔案名稱。
  8. 重新啟動 Jenkins 伺服器。

  9. 確認防火牆已開啟通訊埠 8443,並透過通訊埠 8443 存取 Jenkins。

  10. 安裝將 Keycloak 與 Jenkins 整合所需的 Jenkins 外掛程式。你可以選擇下列其中一種方式:

    如要安裝外掛程式,請按照下列步驟操作:

    1. 在 Jenkins 資訊主頁中,依序前往「Manage Jenkins」>「Manage Plugins」
    2. 選取「可用」,然後搜尋所需外掛程式。下圖顯示外掛程式管理員,並選取「可用」分頁。

      Jenkins 外掛程式管理員。

    3. 安裝外掛程式。

設定 Keycloak

在本教學課程中,Keycloak 會管理使用者、群組和角色。Keycloak 會使用領域管理使用者。

  1. 在外部執行的 VM 上 Google Cloud,安裝 Keycloak 伺服器。在本教學課程中,建議您從 Docker 容器安裝 Keycloak

  2. 開啟 Keycloak 管理控制台。

  3. 前往「領域設定」

  4. 在「一般」分頁中,確認欄位設定如下:

    • 已啟用開啟
    • 使用者管理存取權關閉
    • 端點OpenID 端點設定SAML 2.0 身分識別提供者中繼資料

    下圖顯示您必須設定的欄位。

    Keycloak 一般設定。

  5. 建立用戶端,這樣您就有實體可以要求 Keycloak 驗證使用者。用戶端通常是應用程式和服務,會使用 Keycloak 提供單一登入 (SSO) 解決方案。

    1. 在 Keycloak 管理主控台中,依序點選「Clients」>「Create」
    2. 輸入下列指令:

      • 用戶端 IDjenkins
      • 用戶端通訊協定openid-connect
      • 根網址http://JENKINS_IP_ADDRESS:8080,其中 JENKINS_IP_ADDRESS 是 Jenkins 伺服器的 IP 位址。

      下圖顯示您必須設定的欄位。

      Keycloak 新增用戶端。

    3. 按一下 [儲存]

  6. 在「安裝」分頁中,確認權杖格式為「Keycloak OIDC JSON」。請複製這個權杖,因為您需要這個權杖才能完成 Jenkins 設定。

  7. 如要建立測試群組,請按照下列步驟操作:

    1. 在 Keycloak 管理控制台中,依序點選「Groups」>「New」
    2. 輸入群組名稱,然後按一下「儲存」
    3. 再建立一個測試群組。您可以為群組指派角色,但本教學課程不需要這麼做。
  8. 如要建立測試使用者並加入群組,請按照下列步驟操作:

    1. 在 Keycloak 管理控制台中,依序按一下「Manage user」>「Add users」
    2. 填寫使用者資訊,然後按一下「儲存」

      下方的螢幕截圖顯示使用者帳戶的範例資訊。

      Keycloak 新增使用者。

    3. 按一下「憑證」分頁標籤,確認「暫時」已設為「關閉」

    4. 重設密碼。

      您稍後會在 JWT 中使用這個帳戶進行驗證。

      下圖顯示「憑證」分頁,以及您必須設定的欄位。

      Keycloak 變更密碼。

    5. 按一下「群組」分頁標籤,然後選取先前建立的其中一個群組。

    6. 按一下 [加入]

    7. 重複這個步驟,建立更多測試使用者。

設定 Jenkins 的 OpenID Connect 設定

本節說明如何設定 Jenkins 的 OpenID Connect 外掛程式。

  1. 在 Jenkins 伺服器上,依序前往「Manage Jenkins」>「Configure Global Security」
  2. 在「Security Realm」下方,選取「Keycloak Authentication Plugin」。按一下「儲存」

  3. 按一下「設定系統」

  4. 在「Global Keycloak」設定下方,複製您在「設定 Keycloak」中建立的 Keycloak 安裝 JSON。 如要再次取得 JSON 資料,請完成下列步驟:

    1. 在 Keycloak 管理控制台中,前往「Clients」

    2. 按一下客戶名稱。

    3. 在「安裝」分頁中,按一下「格式選項」,然後選取「Keycloak OIDC JSON」

    以下是 Keycloak JSON 的範例:

    {
        "realm":"master"
        "auth-server-url":"AUTHSERVERURL"
        "ssl-required":"none"
        "resource":"jenkins"
        "public-client":true
        "confidential-port":0
    }
    

    AUTHSERVERURL 是驗證伺服器的網址。

  5. 如要儲存 OIDC 設定,請按一下「儲存」

Jenkins 現在可以重新導向至 Keycloak,以取得使用者資訊。

安裝 Cloud 用戶端程式庫

如要從 Keycloak 將 JWT 傳送至 Google Cloud,您必須在 Jenkins 伺服器上安裝 Cloud 用戶端程式庫。本教學課程會使用 Python,透過 SDK 與Google Cloud 互動。

  1. 在 Jenkins 伺服器上安裝 Python。下列步驟說明如何安裝 python3:

    sudo apt update
    sudo apt install software-properties-common
    sudo add-apt-repository ppa:deadsnakes/ppa
    sudo apt update
    sudo apt install python3.8
    
  2. 安裝 pip3,以便下載及匯入 Cloud 用戶端程式庫

    pip3 –version
    sudo apt update
    sudo apt install python3-pip
    pip3 –version
    
  3. 使用 pip3 安裝 Python 適用的 Cloud 用戶端程式庫

    pip3 install –upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib
    

    例如:

    pip3 install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib
    Collecting google-api-python-client
        Downloading google_api_python_client-2.42.0-py2.py3-none-any.whl (8.3 MB)
            USERNAME | 8.3 MB 19.9 MB/s
    Collecting google-auth-httplib2
        Downloading google_auth_httplib2-0.1.0-py2.py3-none-any.whl (9.3 MB)
    Collecting google-auth-oauthlib
    Downloading google_auth_oauthlib-0.5.1-py2.py3-non-any.whl (19 KB)
    

    USERNAME 替換成您的使用者名稱。

  4. 在 Jenkins 伺服器上安裝 Google Cloud CLI。如需操作說明,請參閱「快速入門:安裝 gcloud CLI」。

設定 Google Cloud 環境

本節說明必須完成的步驟,確保託管無伺服器容器的Google Cloud 環境可以連線至 Jenkins 和 Keycloak。

  1. 在 Google Cloud中,建立服務帳戶,讓 Cloud Run 上的微服務可以存取附加的權限。舉例來說,如要使用 gcloud CLI 建立服務帳戶,請執行下列操作:

    gcloud iam service-accounts create cloudrun-oidc \
      –-description="cloud run oidc sa"  \
      –-display-name="cloudrun-oidc"
    

    根據預設,Cloud Run 會為您建立預設服務帳戶。不過,使用預設服務帳戶並非安全最佳做法,因為該帳戶的權限範圍很廣。因此,建議您為微服務建立專屬的服務帳戶。如需建立 Cloud Run 服務帳戶的操作說明,請參閱建立及管理服務帳戶

  2. 建立工作負載身分集區。如要使用 gcloud CLI 建立集區,請執行下列指令:

    gcloud iam workload-identity-pools create cloudrun-oidc-pool \
      --location="global" \
      —-description="cloudrun-oidc" \
      —-display-name="cloudrun-oidc"
    
  3. 為 OpenID Connect 建立 workload identity pool 提供者:

    gcloud iam workload-identity-pools providers create-oidc cloud-run-provider \
      --workload-identity-pool="cloudrun-oidc-pool" \
      --issuer-uri="VAR_LINK_TO_ENDPOINT" \
      --location="global" \
      --attribute-mapping ="google.subject=assertion.sub,attribute.isadmin-assertion.isadmin,attribute.aud=assertion.aud" \
      --attribute-condition="attribute.isadmin=='true'"
    

    VAR_LINK_TO_ENDPOINT 替換為包含 Keycloak OIDC 端點連結的變數。如要尋找這個連結,請在 KeyCloud 管理控制台的「Realm」視窗中,按一下「General」分頁標籤。 端點必須是 HTTPS,也就是說,您必須使用 HTTPS 設定 Keycloak 伺服器。

從 Keycloak 取得通過驗證的使用者 JWT

  1. 在執行 Keycloak 的 VM 上,將權杖下載為文字檔。舉例來說,在 Linux 上執行下列指令:

    curl -L -X POST 'https://IP_FOR_KEYCLOAK:8080/auth/realms/master/protocol/openid-connect/token' -H 'Content-Type: application/x-www-form-urlencoded' \
      --data-urlencode 'client_id=jenks' \
      --data-urlencode 'grant_type=password' \
      --data-urlencode 'client_secret=CLIENT_SECRET \
      --data-urlencode 'scope=openid' \
      --data-urlencode 'username=USERNAME' \
      --data-urlencode 'password=PASSWORD' | grep access_token | cut -c18-1490 > token.txt
    

    更改下列內容:

    • IP_FOR_KEYCLOAK,並將其替換為 Keycloak 伺服器 IP 位址。
    • CLIENT_SECRET 改成 Keycloak 用戶端密鑰。
    • USERNAME與 Keycloak 使用者。
    • PASSWORD,並輸入 Keycloak 使用者的密碼。

    這個指令包含用戶端 ID、用戶端密鑰、使用者名稱和密碼。為確保安全性,建議您使用環境變數遮蓋這些值,而不是使用指令列。範例指令會將憑證重新導向至名為 token.txt 的檔案。

    如要自動執行這個步驟,可以選擇建立 Bash 指令碼。

  2. jwt.io 驗證權杖。

  3. 在 VM 上建立憑證檔案:

    gcloud iam workload-identity-pools create-cred-config \
    projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/cloudrun-oidc-pool/providers/cloud-run/provider \
      --output-file=sts-creds.json \
      --credential-source-file=token.txt
    

    詳情請參閱「gcloud iam workload-identity-pools create-cred-config」。

    輸出檔案應如下所示:

    {
        "type": "external_account",
        "audience": "//iam.google.apis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/cloudrun-oidc-pool/subject/USER_EMAIL",
        "subject_token_type": "urn:ietf:params:oauth:token-type:jwt",
        "token_url": "https://sts.googleapis.com/v1/token",
        "credential_source": {
            "file" "token.txt" }
    }
    

    PROJECT_NUMBER 是您的專案號碼。

  4. 在 VM 上,將 sts.creds.json 檔案設為 ADC 的變數:

    export GOOGLE_APPLICATION_CREDENTIALS=/Users/USERNAME/sts-creds.json
    

    USERNAME 替換成您的 UNIX 使用者名稱。

    在 Workload Identity Federation 推出前,這個值是服務帳戶金鑰。使用 Workload Identity 聯盟時,這個值是新建立的憑證檔案。

  5. 為使用者建立角色繫結,模擬服務帳戶:

    gcloud iam service-accounts add-iam-policy-binding SERVICE_ACCOUNT \
        --role roles/iam.workloadIdentityUser \
        --member "principal://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/cloudrun-oidc-pool/subject/USER_EMAIL
    

    更改下列內容:

  6. 允許服務帳戶存取 Cloud Run 服務:

    gcloud run services add-iam-policy-binding SERVICE_NAME
      --member-"serviceAccount:SERVICE_ACCOUNT" \
      --role="roles/run.invoker"
    

    更改下列內容:

    • SERVICE_NAME,換成在 Cloud Run 上執行的微服務名稱。

    • SERVICE_ACCOUNT,並填入 Cloud Run 服務帳戶的電子郵件地址。

    詳情請參閱 gcloud run services add-iam-policy-binding

  7. 產生 ID 權杖:

    #!/usr/bin/python
    from google.auth import credentials
    from google.cloud import iam_credentials_v1
    
    import google.auth
    import google.oauth2.credentials
    
    from google.auth.transport.requests import AuthorizedSession, Request
    
    url = "https://WORKLOAD_FQDN"
    aud = "https://WORKLOAD_FQDN"
    service_account = 'SERVICE_ACCOUNT'
    
    client = iam_credentials_v1.IAMCredentialsClient()
    
    name = "projects/-/serviceAccounts/{}".format(service_account)
    id_token = client.generate_id_token(name=name,audience=aud, include_email=True)
    
    print(id_token.token)
    
    creds = google.oauth2.credentials.Credentials(id_token.token)
    authed_session = AuthorizedSession(creds)
    r = authed_session.get(url)
    print(r.status_code)
    print(r.text)
    

    更改下列內容:

    • WORKLOAD_FQDN 替換為工作負載的 FQDN。

    • SERVICE_ACCOUNT,並填入 Cloud Run 服務帳戶的電子郵件地址。

您使用的權杖可以呼叫 Identity and Access Management API,取得呼叫 Cloud Run 服務所需的新 JWT。

您可以在 Jenkins 管道中使用權杖,叫用在 Cloud Run 中執行的無伺服器容器。不過,這些步驟不在本教學課程的討論範圍內。

清除所用資源

如要避免系統向您的 Google Cloud 帳戶收取本教學課程所用資源的費用,請刪除專案。

刪除專案

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

後續步驟