本页介绍如何从用户账号或服务账号向受 Identity-Aware Proxy (IAP) 保护的资源进行身份验证。
在程序化访问场景中,您可以从非浏览器客户端调用受 IAP 保护的应用。这包括命令行工具、服务到服务调用和移动应用。根据您的用例,您可能需要使用用户凭据或服务凭据向 IAP 进行身份验证。
用户账号属于个别用户。当您的应用需要代表用户访问受 IAP 保护的资源,则对用户账号进行身份验证。如需了解详情,请参阅用户账号。
服务账号代表应用,而非个别用户。如果要允许应用访问受 IAP 保护的资源,则对服务账号进行身份验证。如需了解详情,请参阅服务账号。
IAP 支持以下类型的凭据以实现程序化访问:
- OAuth 2.0 ID 令牌 - 由 Google 为真人用户或服务账号签发的令牌,其中目标对象声明设置为 IAP 应用的资源 ID。
- 服务账号签名的 JWT - 服务账号的自签名或 Google 签发的 JWT 令牌。
在 Authorization
或 Proxy-Authorization
HTTP 标头中将这些凭据传递给 IAP。
准备工作
在开始之前,您需要有一个受 IAP 保护的应用,并且需要使用开发者账号、服务账号或移动应用凭据以编程方式连接到该应用。
对用户账号进行身份验证
您可以允许用户从桌面应用或移动应用访问您的应用,从而支持程序与受 IAP 保护的资源进行交互。
从移动应用进行身份验证
- 为您的移动应用创建或使用现有的 OAuth 2.0 客户端 ID。如需使用现有的 OAuth 2.0 客户端 ID,请按照如何共享 OAuth 客户端中的步骤操作。将 OAuth 客户端 ID 添加到许可名单,以便为应用提供程序化访问权限。
- 为受 IAP 保护的客户端 ID 获取一个 ID 令牌。
- Android:使用 Google Sign-In API 请求 OpenID Connect (OIDC) 令牌。将
requestIdToken
客户端 ID 设置为您要连接的资源的客户端 ID。 - iOS:使用 Google 登录获取 ID 令牌。
- Android:使用 Google Sign-In API 请求 OpenID Connect (OIDC) 令牌。将
- 在
Authorization: Bearer
标头中包含 ID 令牌以向受 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 值,将其替换为以下命令中的
AUTH_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
此命令会返回一个带有
id_token
字段的 JSON 对象,您可以使用该字段访问应用。
访问应用
如需访问该应用,请使用 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
此命令会返回一个带有新 id_token
字段的 JSON 对象,您可以使用该字段访问应用。
对服务账号进行身份验证
您可以使用服务账号 JWT 或 OpenID Connect (OIDC) 令牌向受 IAP 保护的资源对服务账号进行身份验证。下表概述了不同身份验证令牌及其功能之间的一些差异。
Authentication 功能 | 服务账号 JWT | OpenID Connect 令牌 |
---|---|---|
情境感知访问权限支持 | ||
OAuth 2.0 客户端 ID 要求 | ||
令牌作用域 | 受 IAP 保护的资源的网址 | OAuth 2.0 客户端 ID |
使用服务账号 JWT 进行身份验证
IAP 支持为配置了 Google 身份、Identity Platform 和 Workforce Identity Federation 的应用使用服务账号 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.iam.gserviceaccount.com
对于
aud
字段,请指定使用 IAP 保护的资源的网址。对于
iat
字段,请指定当前的 Unix 纪年时间;对于exp
字段,请指定 3600 秒后的某个时间。此属性用于定义 JWT 的到期时间。
为 JWT 签名
您可以使用以下任一方法为 JWT 签名:
- 使用 IAM 凭据 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 service account JWT is created for.
resource_url (str): Specifies 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 protected application.
Returns:
str: A signed JWT that can be used to access IAP protected apps.
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
# If project_id is None, use '-' as placeholder as per API requirements
project = project_id if project_id else "-"
name = iam_client.service_account_path(project, 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.googleapis.com/v1/projects/-/serviceAccounts/SERVICE_ACCOUNT_EMAIL_ADDRESS:signJwt"
请求成功后,响应中会返回已签名的 JWT。
使用 JWT 访问受 IAP 保护的资源。
使用本地凭据密钥文件为 JWT 签名
JWT 使用服务账号的私钥进行签名。
如果您有服务账号密钥文件,则可以在本地为 JWT 签名。
该脚本会随载荷一起发送 JWT 标头。对于标头中的 kid
字段,请使用服务账号的私钥 ID,该 ID 位于服务账号凭据 JSON 文件的 private_key_id
字段中。该密钥还用于为 JWT 签名。
访问应用
在所有情况下,如需访问该应用,请使用 signed-jwt
:
curl --verbose --header 'Authorization: Bearer SIGNED_JWT' URL
使用 OIDC 令牌进行身份验证
- 创建或使用现有的 OAuth 2.0 客户端 ID。如需使用现有的 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 密钥文件中提取服务账号密钥信息
- 创建包含必要字段的 JWT,包括将 IAP 客户端 ID 用作目标对象
- 使用服务账号的私钥对 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 令牌
在所有其他情况下,请在访问受 IAP 保护的资源之前,通过模拟目标服务账号,使用 IAM Credentials API 生成 OIDC 令牌。此过程包括以下步骤:
为发起调用的服务账号(与获取 ID 令牌的代码关联的服务账号)提供 Service Account OpenID Connect Identity Token Creator 角色 (
roles/iam.serviceAccountOpenIdTokenCreator
)。这样,调用方服务账号便可以模拟目标服务账号。
使用调用方服务账号提供的凭据对目标服务账号调用 generateIdToken 方法。
将
audience
字段设置为您的客户端 ID。
如需查看分步说明,请参阅创建 ID 令牌。
从 Proxy-Authorization 标头进行身份验证
如果您的应用使用 Authorization
请求标头,您可以改为在 Proxy-Authorization: Bearer
标头中添加 ID 令牌。如果在 Proxy-Authorization
标头中找到了有效的 ID 令牌,则 IAP 会用它授权请求。授权请求后,IAP 会将 Authorization
标头传递给您的应用,而不处理内容。
如果在 Proxy-Authorization
标头中未找到有效的 ID 令牌,则 IAP 会继续处理 Authorization
标头并在将请求传递给应用之前去除 Proxy-Authorization
标头。
后续步骤
- 详细了解 Authorization: Bearer 令牌。
- 尝试 Android 登录或 iOS 登录。