集成 Cloud Run 和工作负载身份联合


本教程介绍了如何使用工作负载身份联合对 Google Cloud 外部运行的工作负载进行身份验证,以便它们可以访问由 Cloud Run 托管的微服务。本教程适用于希望将工作负载身份联合与现有身份提供方 (IdP) 集成的管理员。借助工作负载身份联合,您可以将外部工作负载连接到 Google Cloud 中运行的工作负载。Cloud Run 可让您运行无状态容器化微服务。

本教程介绍了如何将 Jenkins 配置为外部工作负载,将 Keycloak 配置为 IdP、Cloud Run 以及工作负载身份联合。完成本教程后,您可以了解工作负载身份联合如何让您使用 OpenID Connect 身份验证通过 Google Cloud 对 Jenkins 应用进行身份验证。

使用工作负载身份联合进行外部工作负载身份验证

借助工作负载身份联合,您无需使用静态服务账号密钥即可对 Google Cloud 外部的工作负载进行身份验证。任何需要使用 Google Cloud 中的服务的外部工作负载都可以从此功能中受益。

工作负载身份联合可让您使用 IdP 直接向 Google Cloud 进行身份验证。要进行身份验证,请使用 OpenID Connect。Cloud Run 接受来自 IdP 的 OpenID Connect 令牌进行身份验证。

使用工作负载身份联合时的身份验证过程如下所示:

  1. 您的身份验证 (AUTHN) 库会向 IdP 发送 JSON Web 令牌 (JWT) 请求。
  2. IdP 对 JSON Web 令牌 (JWT) 签名。AUTHN 库从变量中读取此数据。
  3. 该库会向包含签名令牌的 Security Token Service 发送 POST 命令。
  4. Security Token Service 会查看您配置的工作负载身份池提供方以建立信任并验证凭据上的身份。
  5. Security Token Service 会发回联合令牌。
  6. 该库将此令牌发送到 IAM。
  7. IAM 将此令牌交换为服务账号的 OpenID Connect 令牌。如需了解详情,请参阅生成 OpenID Connect ID 令牌
  8. 该库向 Jenkins 提供 OpenID Connect 令牌。
  9. Jenkins 使用此令牌向 Cloud Run 进行身份验证。

下图演示了身份验证流程:

身份验证流程。

目标

  • 将 Jenkins 配置为外部工作负载。
  • Keycloak 配置为与 OpenID Connect 兼容的 IdP。
  • 将 Jenkins 与 Keycloak 连接。
  • 安装 Cloud 客户端库,以将 JWT 令牌从 Keycloak 获取到 Google Cloud。
  • 将 Google Cloud 连接到 Keycloak 和 Jenkins。
  • 从 Keycloak 获取经过身份验证的用户的 JWT。

虽然本教程使用 Keycloak,但您可以使用支持 OpenID Connect 的任何身份提供方,例如 GitLab、Okta 或 OneLogin。

费用

在本文档中,您将使用 Google Cloud 的以下收费组件:

您可使用价格计算器根据您的预计使用情况来估算费用。 Google Cloud 新用户可能有资格申请免费试用

完成本文档中描述的任务后,您可以通过删除所创建的资源来避免继续计费。如需了解详情,请参阅清理

准备工作

  1. 在 Google Cloud Console 中,转到项目选择器页面。

    转到“项目选择器”

  2. 选择或创建 Google Cloud 项目。

  3. 确保您的 Google Cloud 项目已启用结算功能

  4. 在 Cloud Run 上设置微服务。如需了解详情,请参阅《快速入门:将容器部署到 Cloud Run》

配置 Jenkins

请在非 Google Cloud 环境(例如本地环境或其他云中)中完成这些任务。

如果您已有支持 OpenID Connect 和外部工作负载的身份提供方,则可以跳过此步骤并转到安装 Cloud 客户端库

如需模拟外部工作负载,您可以使用安装了 Jenkins 的虚拟机。您可以将 Jenkins 作为 Docker 映像运行,也可以直接将其安装到服务器中。以下步骤演示了如何直接将 Jenkins 安装在服务器上。

  1. 在您选择的虚拟机上,打开命令行。
  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.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 服务器。如果您使用的是位于防火墙后面的虚拟机,请确保相应的端口处于开放状态。

  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 替换为 Google Cloud 外部的服务器的 FQDN。
      • 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 信息中心,转到管理 Jenkins > 管理插件
    2. 选择 Available,然后搜索您选择的插件。以下屏幕截图展示了已选定 Available 标签页的插件管理器。

      Jenkins 插件管理器。

    3. 安装插件。

配置 Keycloak

在本教程中,Keycloak 用于管理用户、群组和角色。Keycloak 使用大区来管理用户。

  1. 在 Google Cloud 外部运行的虚拟机上,安装 Keycloak 服务器。在本教程中,我们建议您从 Docker 容器安装 Keycloak

  2. 打开 Keycloak 管理控制台。

  3. 前往 Realm settings

  4. General 标签页中,验证字段是否按如下所示设置:

    • 已启用开启
    • User-Managed AccessOFF
    • 端点OpenID 端点配置SAML 2.0 身份提供方元数据

    以下屏幕截图展示了您必须配置的字段。

    Keycloak 常规设置。

  5. 创建客户端,以便您有一个可以请求 Keycloak 对用户进行身份验证的实体。通常,客户端是使用 Keycloak 提供单点登录 (SSO) 解决方案的应用和服务。

    1. 在 Keycloak 管理控制台中,点击 Clients > Create
    2. 输入以下内容:

      • Client IDjenkins
      • 客户端协议openid-connect
      • Root URLhttp://JENKINS_IP_ADDRESS:8080,其中 JENKINS_IP_ADDRESS 是 Jenkins 服务器的 IP 地址。

      以下屏幕截图展示了您必须配置的字段。

      Keycloak 添加客户端。

    3. 点击保存

  6. 安装标签页中,验证令牌格式是否为 Keycloak OIDC JSON。请创建此令牌的副本,因为您在完成 Jenkins 设置时需要用到它。

  7. 要创建测试群组,请执行以下操作:

    1. 在 Keycloak 管理控制台中,点击 Groups > New
    2. 输入群组的名称,然后点击 Save
    3. 再创建一个测试群组。您可以为群组分配角色,但本教程不需要这些角色。
  8. 如需创建要添加到群组的测试用户,请执行以下操作:

    1. 在 Keycloak 管理控制台中,点击 Manage user > Add users
    2. 填写用户信息,然后点击 Save

      以下屏幕截图展示了用户账号的示例信息。

      Keycloak 添加用户。

    3. 点击 Credentials 标签页,然后验证 Temporary 是否设置为 Off

    4. 重置密码。

      您稍后将在 JWT 中使用此账号进行身份验证。

      以下屏幕截图展示了 Credentials 标签页,其中包含您必须配置的字段。

      Keycloak 更改密码。

    5. 点击 Groups 标签页,然后选择您之前创建的一个群组。

    6. 点击加入

    7. 重复执行此步骤,创建更多测试用户。

为 OpenID Connect 配置 Jenkins

本部分介绍如何为 Jenkins 配置 OpenID Connect 插件。

  1. 在 Jenkins 服务器上,依次点击 Manage Jenkins > Configure Global Security
  2. 在“安全大区”下,选择 Keycloak 身份验证插件。点击保存

  3. 点击配置系统

  4. Global Keycloak 设置下,复制您在配置 Keycloak 中创建的 Keycloak 安装 JSON。如果您需要再次获取 JSON 数据,请完成以下操作:

    1. 在 Keycloak 管理控制台中,转到客户端

    2. 点击您的客户端名称。

    3. 安装标签页中,点击格式选项,然后选择 Keyclak OIDC JSON

    以下是一个 Keycloak JSON 示例:

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

    AUTHSERVERURL 是您的身份验证服务器的网址。

  5. 如需保存 OIDC 配置,请点击 Save

Jenkins 现在可以重定向到 Keycloak 以获取用户信息。

安装 Cloud 客户端库

如需将 JWT 从 Keycloak 发送到 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 创建工作负载身份池提供方:

    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 的虚拟机上,将令牌下载到文本文件。例如,在 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. 在虚拟机上,创建凭据文件:

    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. 在虚拟机上,将 sts.creds.json 文件设置为 ADC 的变量:

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

    USERNAME 替换为您的 UNIX 用户名。

    在工作负载身份联合发布之前,此值是服务账号密钥。使用工作负载身份联合时,此值是新创建的凭据文件。

  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'
    
    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. 在 Google Cloud 控制台中,进入管理资源页面。

    转到“管理资源”

  2. 在项目列表中,选择要删除的项目,然后点击删除
  3. 在对话框中输入项目 ID,然后点击关闭以删除项目。

后续步骤