本文档介绍了如何使用 X.509 证书为工作负载身份联合配置基于证书的访问权限。
基于证书的访问权限使用双向 TLS (mTLS) 在 TLS 握手期间对客户端和服务器进行身份验证。在此过程中,mTLS 绑定会根据传输上下文纳入政策,并使用 TLS 会话中客户端证书的状态来做出授权决策。
对于 X.509 工作负载身份联合,mTLS 绑定可确保整个身份验证流程安全地关联到可信的工作负载。这样可以降低凭证盗用风险,因为系统会将身份验证绑定到特定的可信端点。
工作负载身份联合配置的基于证书的访问权限概览
下面简要概述了为工作负载身份联合配置基于证书的访问权限的过程:
通过配置与 X.509 证书的信任锚的信任关系,建立工作负载身份联合。
为基于证书的访问权限创建访问权限级别。
将访问权限级别添加到强制执行 mTLS 绑定的情境感知访问权限政策中。
准备工作
验证您是否满足以下前提条件:
最新版本的 Google Cloud CLI。
如需更新到最新版本 gcloud CLI,请运行以下命令:
gcloud components update如果您需要安装 gcloud CLI,请参阅安装 gcloud CLI。
使用 X.509 证书信任锚的工作负载身份联合配置。
如需使用此功能,请填写许可清单申请表单以申请访问权限。
为证书创建访问权限级别
创建 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:访问权限政策的名称。
将您创建的访问权限级别导出到环境变量,以便在后续步骤中使用:
export ACCESS_LEVEL_ID=ACCESS_LEVEL_ID
将
ACCESS_LEVEL_ID替换为访问权限级别名称,例如accessPolicies/12345/accessLevels/acl_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
创建一个包含情境感知访问权限绑定的 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- 单一身份:
使用
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 客户端库向工作负载身份联合工作负载授权,请完成以下步骤:
创建为工作负载身份联合身份验证配置的应用默认凭据 (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 握手。
设置一个环境变量,使其指向 ADC 文件,以便 Google 客户端库能够发现您的凭证:
export GOOGLE_APPLICATION_CREDENTIALS=ADC_FILE_OUTPUT_PATH
如果您在生成 ADC 文件时省略了
--output-file参数,则此步骤为可选步骤。如果您省略该参数,则 gcloud CLI 会从 gcloud CLI 默认配置目录创建和读取 ADC 文件。此功能支持 Go、Python 和 Java 客户端库。您需要设置环境变量,以便为 Python 和 Java 开启 mTLS。
如需快速建立和测试对 Google Cloud API 的 mTLS 访问权限,您可以使用以下代码示例:
Go
使用以下示例创建一个 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替换为您的Google Cloud 项目 ID。如需在 Compute Engine 虚拟机上运行测试,请使用以下命令:
go mod init example.com go mod tidy go test -v golang_test.go --count=1Python
使用以下示例创建测试文件,例如
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替换为您的Google Cloud 项目 ID。如需在 Compute Engine 虚拟机上运行测试,请完成以下步骤:
- 设置 Python 虚拟环境。
安装所需的库:
pip install google-auth google-auth-httplib2 requests运行测试:
python3 python_test.py
使用纯 HTTP 请求进行授权
如需使用纯 HTTP 请求向工作负载身份联合工作负载授权,请完成以下步骤:
通过标准 mTLS 握手从 Google Cloud Security Token Service 获取绑定证书的访问令牌。
使用您从 Security Token Service 获取的访问令牌调用 Google Cloud 服务。此示例会查询 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"
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:?}"