为工作负载身份联合配置基于证书的访问权限

本文档介绍了如何使用 X.509 证书为工作负载身份联合配置基于证书的访问权限。

基于证书的访问权限使用双向 TLS (mTLS) 在 TLS 握手期间对客户端和服务器进行身份验证。在此过程中,mTLS 绑定会根据传输上下文纳入政策,并使用 TLS 会话中客户端证书的状态来做出授权决策。

对于 X.509 工作负载身份联合,mTLS 绑定可确保整个身份验证流程安全地关联到可信的工作负载。这样可以降低凭证盗用风险,因为系统会将身份验证绑定到特定的可信端点。

工作负载身份联合配置的基于证书的访问权限概览

下面简要概述了为工作负载身份联合配置基于证书的访问权限的过程:

  1. 通过配置与 X.509 证书的信任锚的信任关系,建立工作负载身份联合。

  2. 为基于证书的访问权限创建访问权限级别。

  3. 将访问权限级别添加到强制执行 mTLS 绑定的情境感知访问权限政策中。

准备工作

验证您是否满足以下前提条件:

为证书创建访问权限级别

  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 文件:expression: "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/*
      cat <<EOF > request.json
      {
        "principal": {
          "federatedPrincipal": "${FEDERATED_PRINCIPAL:?}"
        },
        "accessLevels": ["${ACCESS_LEVEL_ID:?}"]
      }
      EOF
      
    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"
      

使用 Cloud de Confiance by S3NS 客户端库进行授权

如需使用Cloud de Confiance 客户端库向工作负载身份联合工作负载授权,请完成以下步骤:

  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 默认配置目录中生成证书配置文件。证书配置文件支持初始身份验证,并为后续对 Cloud de Confiance 资源的请求建立 mTLS 握手。

  2. 设置一个环境变量,使其指向 ADC 文件,以便 Google 客户端库能够发现您的凭证:

    export GOOGLE_APPLICATION_CREDENTIALS=ADC_FILE_OUTPUT_PATH
    

    如果您在生成 ADC 文件时省略了 --output-file 参数,则此步骤为可选步骤。如果您省略该参数,则 gcloud CLI 会从 gcloud CLI 默认配置目录创建和读取 ADC 文件。

  3. 此功能支持 Go、Python 和 Java 客户端库。您需要设置环境变量,以便为 Python 和 Java 开启 mTLS。

  4. 如需快速建立和测试对 Cloud de Confiance API 的 mTLS 访问权限,您可以使用以下代码示例:

    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 替换为您的Cloud de Confiance 项目 ID。

    2. 如需在 Compute Engine 虚拟机上运行测试,请使用以下命令:

    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_python_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_python_example()
      

      将 PROJECT_ID 替换为您的Cloud de Confiance 项目 ID。

    2. 如需在 Compute Engine 虚拟机上运行测试,请完成以下步骤:

      1. 设置 Python 虚拟环境。
      2. 安装所需的库:

        pip install google-auth google-auth-httplib2 requests
        
      3. 运行测试:

        python3 python_test.py
        

使用纯 HTTP 请求进行授权

如需使用纯 HTTP 请求向工作负载身份联合工作负载授权,请完成以下步骤:

  1. 通过标准 mTLS 握手从 Cloud de Confiance Security Token Service 获取绑定证书的访问令牌。

  2. 使用您从 Security Token Service 获取的访问令牌调用 Cloud de Confiance 服务。此示例会查询 Cloud Storage:

    curl --key WORKLOAD_KEY_PATH --cert WORKLOAD_CERTIFICATE_PATH \
     -X GET "https://storage.mtls.googleapis.com/RESOURCE_PATH" \
     -H "Authorization: Bearer $ACCESS_TOKEN"
    
  3. mTLS 绑定会强制使用 mTLS。运行以下命令,验证非 mTLS 连接是否失败并显示未经授权错误:

    curl -X GET "https://storage.googleapis.com/RESOURCE_PATH" \
     -H "Authorization: Bearer $ACCESS_TOKEN"
    

列出政策绑定

如需列出工作负载身份联合的政策绑定,请运行以下命令:

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"

更新政策绑定

如需更新政策绑定,请完成以下步骤:

gcloud

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

curl

将新的访问权限级别添加到 request.json 文件中,然后运行以下命令:

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 \
--organization=ORG_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:?}"

后续步骤