程序化访问是指从非浏览器客户端(例如命令行工具、服务到服务调用和移动应用)调用受 IAP 保护的应用。根据您的使用场景,您可能需要使用用户凭据或服务凭据向 IAP 进行身份验证。
用户账号属于个别用户。当您的应用需要代表用户访问受 IAP 保护的资源,则对用户账号进行身份验证。如需了解详情,请参阅用户账号。
- 服务账号代表应用,而不是个别用户。如果您想允许应用访问受 IAP 保护的资源,则需要对服务账号进行身份验证。如需了解详情,请参阅服务账号。
IAP 支持以下类型的凭据,用于程序化访问:
* OAuth 2.0 ID 令牌 - Google 为人类用户或服务账号颁发的令牌,其目标对象声明设置为 IAP 应用的资源 ID。 * 服务账号签名的 JWT - 服务账号的自签名或 Google 签发的 JWT 令牌。在请求的 Authorization 或 Proxy-Authorization HTTP 标头中添加这些 IAP 凭证。
准备工作
确保您有一个要使用开发者账号、服务账号或移动应用凭据以编程方式访问的应用。
如需创建一个或多个 OAuth 2.0 客户端,请参阅程序化访问。
对用户账号进行身份验证
您可以允许用户通过桌面或移动应用访问您的应用,从而允许程序与受 IAP 保护的资源进行交互。
通过移动应用进行身份验证
- 为您的移动应用创建或使用现有的 OAuth 2.0 客户端 ID。如需使用现有的 OAuth 2.0 客户端 ID,请按照如何共享 OAuth 客户端中的步骤操作。将 OAuth 客户端 ID 添加到许可清单中,以便以编程方式访问应用。
- 获取受 IAP 保护的资源的 OAuth 2.0 客户端 ID 的 ID 令牌。
- Android:使用 Google 登录 API 请求 OpenID Connect (OIDC) 令牌。将
requestIdToken客户端 ID 设置为您要连接到的资源的客户端 ID。 - iOS:使用 Google 登录获取 ID 令牌。
- Android:使用 Google 登录 API 请求 OpenID Connect (OIDC) 令牌。将
- 将 ID 令牌添加到
Authorization: Bearer标头中,以便向受 IAP 保护的资源发出经过身份验证的请求。
通过桌面应用进行身份验证
本部分介绍如何使用桌面命令行对用户账号进行身份验证。
- 如需允许开发者从命令行访问您的应用,请创建桌面 OAuth 2.0 客户端 ID 或共享现有桌面 OAuth 客户端 ID。
- 将 OAuth ID 添加到应用的程序化访问许可清单中。
登录应用
每个开发者都必须登录才能访问受 IAP 保护的应用。您可以使用 gcloud CLI 将进程打包到脚本中。以下示例演示了如何使用 curl 登录并生成一个可用于访问应用的令牌:
- 登录有权访问 Google Cloud 资源的账号。
启动一个可回显传入请求的本地服务器。
# Example using Netcat (http://netcat.sourceforge.net/) nc -k -l 4444前往以下 URI,其中
DESKTOP_CLIENT_ID是桌面应用客户端 ID:https://accounts.google.com/o/oauth2/v2/auth?client_id=DESKTOP_CLIENT_ID&response_type=code&scope=openid%20email&access_type=offline&redirect_uri=http://localhost:4444&cred_ref=true在本地服务器输出中,查找请求参数:
GET /?code=CODE&scope=email%20openid%20https://www.googleapis.com/auth/userinfo.email&hd=google.com&prompt=consent HTTP/1.1复制 CODE 值,以替换以下命令中的 CODE,以及桌面应用客户端 ID 和密钥:
curl --verbose \ --data client_id=DESKTOP_CLIENT_ID \ --data client_secret=DESKTOP_CLIENT_SECRET \ --data code=CODE \ --data redirect_uri=http://localhost:4444 \ --data grant_type=authorization_code \ https://oauth2.googleapis.com/token此命令会返回一个 JSON 对象,其中包含一个
id_token字段,您可以使用该字段访问应用。
访问应用
如需访问该应用,请使用 id_token:
curl --verbose --header 'Authorization: Bearer ID_TOKEN' URL
刷新令牌
您可以使用登录流程中生成的刷新令牌来获取新的 ID 令牌。当原始 ID 令牌过期时,此功能非常有用。每个 ID 令牌的有效期约为一小时,在此期间,您可以向特定应用发出多个请求。
以下示例使用 curl 通过刷新令牌获取新的 ID 令牌。
在此示例中,REFRESH_TOKEN 是登录流程中的令牌。
DESKTOP_CLIENT_ID 和 DESKTOP_CLIENT_SECRET 与登录流程中使用的相同:
curl --verbose \
--data client_id=DESKTOP_CLIENT_ID \
--data client_secret=DESKTOP_CLIENT_SECRET \
--data refresh_token=REFRESH_TOKEN \
--data grant_type=refresh_token \
https://oauth2.googleapis.com/token
此命令会返回一个 JSON 对象,其中包含一个可用于访问应用的新 id_token 字段。
对服务账号进行身份验证
您可以使用服务账号 JWT 或 OpenID Connect (OIDC) 令牌,通过受 IAP 保护的资源对服务账号进行身份验证。下表概述了不同身份验证令牌及其功能之间的一些差异。| Authentication 功能 | 服务账号 JWT | OpenID Connect 令牌 |
|---|---|---|
| 情境感知访问权限支持 | ||
| OAuth 2.0 客户端 ID 要求 | ||
| 令牌范围 | 受 IAP 保护的资源的网址 | OAuth 2.0 客户端 ID |
使用服务账号 JWT 进行身份验证
IAP 支持对 Google Identity、Identity Platform 和员工身份联合配置的应用进行服务账号 JWT 身份验证。使用 JWT 对服务账号进行身份验证涉及以下步骤:
向调用服务账号授予 Service Account Token Creator 角色 (
roles/iam.serviceAccountTokenCreator)。该角色向主账号授予创建短期有效凭据(例如 JWT)的权限。
为受 IAP 保护的资源创建 JWT。
使用服务账号私钥对 JWT 进行签名。
创建 JWT
创建的 JWT 应具有类似于以下示例的载荷:
{
"iss": SERVICE_ACCOUNT_EMAIL_ADDRESS,
"sub": SERVICE_ACCOUNT_EMAIL_ADDRESS,
"aud": TARGET_URL,
"iat": IAT,
"exp": EXP,
}
对于
iss和sub字段,请指定服务账号的电子邮件地址。电子邮件地址位于服务账号 JSON 文件的client_email字段中,或作为输入提供。典型格式:service-account@PROJECT_ID.对于
aud字段,请指定受 IAP 保护的资源的确切网址或带有路径通配符 (/*) 的网址,例如https://example.com/或https://example.com/*。aud字段中包含确切网址的 JWT 只能访问该特定网址。aud字段中包含路径通配符 (/*) 的 JWT 可以访问所有以aud字符串(不含尾随*)为前缀的网址。对于
iat字段,请指定当前的 Unix 纪元时间;对于exp字段,请指定 3600 秒内的时间。这定义了 JWT 的到期时间。
对 JWT 签名
您可以使用以下任一方法为 JWT 签名:
- 使用 IAM Credentials API 对 JWT 进行签名,而无需直接访问私钥。
- 使用本地凭证密钥文件在本地为 JWT 签名。
使用 IAM Service Account Credentials API 为 JWT 签名
使用 IAM Service Account Credentials API 为服务账号 JWT 签名。该方法会提取与您的服务账号关联的私钥,并使用该私钥对 JWT 载荷进行签名。这样,无需直接访问私钥即可对 JWT 进行签名。
如需向 IAP 进行身份验证,请设置应用默认凭证。如需了解详情,请参阅为本地开发环境设置身份验证。
gcloud
- 运行以下命令,准备一个包含 JWT 载荷的请求:
cat > claim.json << EOM
{
"iss": "SERVICE_ACCOUNT_EMAIL_ADDRESS",
"sub": "SERVICE_ACCOUNT_EMAIL_ADDRESS",
"aud": "TARGET_URL",
"iat": $(date +%s),
"exp": $((`date +%s` + 3600))
}
EOM
- 使用以下 Google Cloud CLI 命令对
claim.json中的载荷进行签名:
gcloud iam service-accounts sign-jwt --iam-account="SERVICE_ACCOUNT_EMAIL_ADDRESS" claim.json output.jwt
请求成功后,output.jwt 会包含一个已签名的 JWT,您可以使用该 JWT 访问受 IAP 保护的资源。
Python
import datetime
import json
import google.auth
from google.cloud import iam_credentials_v1
def generate_jwt_payload(service_account_email: str, resource_url: str) -> str:
"""Generates JWT payload for service account.
Creates a properly formatted JWT payload with standard claims (iss, sub,
aud, iat, exp) needed for IAP authentication.
Args:
service_account_email (str): Specifies the service account that the
JWT is created for.
resource_url (str): Specifies the scope of the JWT, the URL that the
JWT will be allowed to access.
Returns:
str: JSON string containing the JWT payload with properly formatted
claims.
"""
# Create current time and expiration time (1 hour later) in UTC
iat = datetime.datetime.now(tz=datetime.timezone.utc)
exp = iat + datetime.timedelta(seconds=3600)
# Convert datetime objects to numeric timestamps (seconds since epoch)
# as required by JWT standard (RFC 7519)
payload = {
"iss": service_account_email,
"sub": service_account_email,
"aud": resource_url,
"iat": int(iat.timestamp()),
"exp": int(exp.timestamp()),
}
return json.dumps(payload)
def sign_jwt(target_sa: str, resource_url: str) -> str:
"""Signs JWT payload using ADC and IAM credentials API.
Uses Google Cloud's IAM Credentials API to sign a JWT. This requires the
caller to have iap.webServiceVersions.accessViaIap permission on the
target service account.
Args:
target_sa (str): Service Account JWT is being created for.
iap.webServiceVersions.accessViaIap permission is required.
resource_url (str): Audience of the JWT and scope of the JWT token.
This is the URL of the IAP-secured application.
Returns:
str: A signed JWT that can be used to access IAP-secured applications.
Use in Authorization header as: 'Bearer <signed_jwt>'
"""
# Get default credentials from environment or application credentials
source_credentials, project_id = google.auth.default()
# Initialize IAM credentials client with source credentials
iam_client = iam_credentials_v1.IAMCredentialsClient(credentials=source_credentials)
# Generate the service account resource name.
# Project should always be "-".
# Replacing the wildcard character with a project ID is invalid.
name = iam_client.service_account_path("-", target_sa)
# Create and sign the JWT payload
payload = generate_jwt_payload(target_sa, resource_url)
# Sign the JWT using the IAM credentials API
response = iam_client.sign_jwt(name=name, payload=payload)
return response.signed_jwt
curl
运行以下命令,准备一个包含 JWT 载荷的请求:
cat << EOF > request.json { "payload": JWT_PAYLOAD } EOF使用 IAM 为 JWT 签名
Service Account Credentials API:
curl -X POST \ -H "Authorization: Bearer $(gcloud auth print-access-token)" \ -H "Content-Type: application/json; charset=utf-8" \ -d @request.json \ "https://iamcredentials./v1/projects/-/serviceAccounts/SERVICE_ACCOUNT_EMAIL_ADDRESS:signJwt"请求成功后,响应中会返回已签名的 JWT。
使用 JWT 访问受 IAP 保护的资源。
使用本地凭证密钥文件为 JWT 签名
JWT 使用服务账号的私钥进行签名。
如果您有服务账号密钥文件,则可以在本地为 JWT 签名。
在本地为 JWT 签名时,请在载荷中添加 JWT 标头。对于标头中的 kid 字段,请使用服务账号的私钥 ID,该 ID 位于服务账号凭证 JSON 文件的 private_key_id 字段中。文件中的私钥用于为 JWT 签名。
访问应用
如需访问应用,请在 Authorization 标头中添加已签名的 JWT:
curl --verbose --header 'Authorization: Bearer SIGNED_JWT' URL
使用服务账号 OIDC 令牌进行身份验证
如需使用服务账号 OIDC 令牌进行身份验证,请执行以下操作:
创建新的 OIDC 客户端 ID 或使用现有 ID。
如需创建新的 OAuth 2.0 客户端 ID,请执行以下操作:
确保您已注册应用以使用 Google Auth(如果您尚未注册)。
前往 Google Auth Platform 页面。
如果您未选择项目,系统会提示您创建一个项目。
点击创建客户端。
选择适当的应用类型,然后输入所需的任何其他信息。
填写所选客户类型的必填信息。如需创建客户端,请点击创建。
如需使用现有 OAuth 2.0 客户端 ID:请按照如何共享 OAuth 客户端中的步骤操作。
将 OAuth ID 添加到应用的程序化访问许可清单中。
确保将默认服务账号添加到受 IAP 保护的项目的访问权限列表中。
向受 IAP 保护的资源发出请求时,您必须在 Authorization 标头中添加令牌:Authorization: 'Bearer OIDC_TOKEN'
以下代码示例演示了如何获取 OIDC 令牌。
获取默认服务账号的 OIDC 令牌
如需获取 Compute Engine、App Engine 或 Cloud Run 的默认服务账号的 OIDC 令牌,请参考以下代码示例生成用于访问受 IAP 保护的资源的令牌:
C#
如需向 IAP 进行身份验证,请设置应用默认凭据。 如需了解详情,请参阅为本地开发环境设置身份验证。
Go
如需向 IAP 进行身份验证,请设置应用默认凭据。如需了解详情,请参阅为本地开发环境设置身份验证。
Java
如需向 IAP 进行身份验证,请设置应用默认凭据。如需了解详情,请参阅为本地开发环境设置身份验证。
Node.js
如需向 IAP 进行身份验证,请设置应用默认凭据。如需了解详情,请参阅为本地开发环境设置身份验证。
PHP
如需向 IAP 进行身份验证,请设置应用默认凭据。如需了解详情,请参阅为本地开发环境设置身份验证。
Python
如需向 IAP 进行身份验证,请设置应用默认凭据。如需了解详情,请参阅为本地开发环境设置身份验证。
Ruby
如需向 IAP 进行身份验证,请设置应用默认凭据。如需了解详情,请参阅为本地开发环境设置身份验证。
从本地服务账号密钥文件获取 OIDC 令牌
如需使用服务账号密钥文件生成 OIDC 令牌,请使用密钥文件创建并签署 JWT 断言,然后用该断言换取 ID 令牌。以下 Bash 脚本演示了此过程:
Bash
#!/usr/bin/env bash
#
# Example script that generates an OIDC token using a service account key file and uses it to access an IAP-secured resource.
set -euo pipefail
get_token() {
# Get the bearer token in exchange for the service account credentials
local service_account_key_file_path="${1}"
local iap_client_id="${2}"
# Define the scope and token endpoint
local iam_scope="https://www.googleapis.com/auth/iam"
local oauth_token_uri="https://www.googleapis.com/oauth2/v4/token"
# Extract data from service account key file
local private_key_id="$(cat "${service_account_key_file_path}" | jq -r '.private_key_id')"
local client_email="$(cat "${service_account_key_file_path}" | jq -r '.client_email')"
local private_key="$(cat "${service_account_key_file_path}" | jq -r '.private_key')"
# Set token timestamps (current time and expiration 10 minutes later)
local issued_at="$(date +%s)"
local expires_at="$((issued_at + 600))"
# Create JWT header and payload
local header="{'alg':'RS256','typ':'JWT','kid':'${private_key_id}'}"
local header_base64="$(echo "${header}" | base64 | tr -d '\n')"
local payload="{'iss':'${client_email}','aud':'${oauth_token_uri}','exp':${expires_at},'iat':${issued_at},'sub':'${client_email}','target_audience':'${iap_client_id}'}"
local payload_base64="$(echo "${payload}" | base64 | tr -d '\n')"
# Create JWT signature using the private key
local signature_base64="$(printf %s "${header_base64}.${payload_base64}" | openssl dgst -binary -sha256 -sign <(printf '%s\n' "${private_key}") | base64 | tr -d '\n')"
local assertion="${header_base64}.${payload_base64}.${signature_base64}"
# Exchange the signed JWT assertion for an ID token
local token_payload="$(curl -s \
--data-urlencode "grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer" \
--data-urlencode "assertion=${assertion}" \
https://www.googleapis.com/oauth2/v4/token)"
# Extract just the ID token from the response
local bearer_id_token="$(echo "${token_payload}" | jq -r '.id_token')"
echo "${bearer_id_token}"
}
main() {
# Check if required arguments are provided
if [[ $# -lt 3 ]]; then
echo "Usage: $0 <service_account_key_file.json> <iap_client_id> <url>"
exit 1
fi
# Assign parameters to variables
SERVICE_ACCOUNT_KEY="$1"
IAP_CLIENT_ID="$2"
URL="$3"
# Generate the ID token
echo "Generating token..."
ID_TOKEN=$(get_token "${SERVICE_ACCOUNT_KEY}" "${IAP_CLIENT_ID}")
# Access the IAP-secured resource with the token
echo "Accessing: ${URL}"
curl --header "Authorization: Bearer ${ID_TOKEN}" "${URL}"
}
# Run the main function with all provided arguments
main "$@"
此脚本会执行以下步骤:
- 从 JSON 密钥文件中提取服务账号密钥信息
- 使用必要字段(包括作为目标受众群体的 IAP 客户端 ID)创建 JWT
- 使用服务账号的私钥对 JWT 进行签名
- 通过 Google 的 OAuth 服务将此 JWT 换成 OIDC 令牌
- 使用生成的令牌向受 IAP 保护的资源发出经过身份验证的请求
如需使用此脚本,请执行以下操作:
- 将其保存到文件中,例如:
get_iap_token.sh - 使其可执行:
chmod +x get_iap_token.sh - 使用以下三个参数运行该命令:
./get_iap_token.sh service-account-key.json \
OAUTH_CLIENT_ID \
URL
其中:
service-account-key.json是您下载的服务账号密钥文件- OAUTH_CLIENT_ID 是受 IAP 保护的资源的 OAuth 客户端 ID
- URL 是您要访问的网址
通过使用服务账号模拟获取 OIDC 令牌
在所有其他情况下,请使用 IAM Credentials API,在访问受 IAP 保护的资源之前,通过模拟目标服务账号来生成 OIDC 令牌。此过程包括以下步骤:
为调用服务账号(与获取 ID 令牌的代码关联的服务账号)提供 Service Account OpenID Connect Identity Token Creator 角色 (
roles/iam.serviceAccountOpenIdTokenCreator)。这样,调用服务账号便可以模拟目标服务账号。
使用调用服务账号提供的凭据对目标服务账号调用 generateIdToken 方法。
将
audience字段设置为您的客户端 ID。
如需查看分步说明,请参阅创建 ID 令牌。
通过 Proxy-Authorization 标头进行身份验证
如果您的应用使用 Authorization 请求标头,则可以将 ID 令牌添加到 Proxy-Authorization: Bearer 标头中。如果在 Proxy-Authorization 标头中找到有效的 ID 令牌,IAP 会使用该令牌对请求进行授权。在对请求进行授权后,IAP 会将 Authorization 标头传递给您的应用,而不会处理内容。
如果在 Proxy-Authorization 标头中未找到有效的 ID 令牌,则 IAP 会继续处理 Authorization 标头并在将请求传递给应用之前去除 Proxy-Authorization 标头。
访问应用
如需使用 Proxy-Authorization 标头访问应用,请运行以下命令:
curl --verbose --header 'Proxy-Authorization: Bearer SIGNED_JWT' URL
后续步骤
- 详细了解授权:不记名令牌。
- 请尝试适用于 Android 的登录功能或适用于 iOS 的登录功能。