程序化身份验证

本页面介绍了如何从用户帐号或服务帐号向受 Identity-Aware Proxy (IAP) 保护的资源进行身份验证。

  • 用户账号属于个别用户。当您的应用需要代表用户访问受 IAP 保护的资源,则对用户账号进行身份验证。如需了解详情,请参阅用户帐号

  • 服务账号属于应用而非个别用户。 如果要允许应用访问受 IAP 保护的资源,则对服务账号进行身份验证。如需了解详情,请参阅服务帐号

准备工作

在开始之前,您需要做好以下准备:

  • 一个受 IAP 保护的应用,您要使用开发者帐号、服务帐号或移动应用凭据以编程方式连接到该应用。

对用户账号进行身份验证

您可以允许用户通过桌面应用或移动应用访问您的应用,以允许程序与受 IAP 保护的资源进行交互。

从移动应用进行身份验证

  1. 为您的移动应用创建或使用现有的 OAuth 2.0 客户端 ID。要使用现有的 OAuth 2.0 客户端 ID,请按照如何共享 OAuth 客户端中的步骤操作。
  2. 将 OAuth 客户端 ID 列入许可名单,以便进行应用的程序化访问
  3. 获取受 IAP 保护的客户端 ID 的 ID 令牌。
  4. Authorization: Bearer 标头中包含 ID 令牌以向受 IAP 保护的资源发出经过身份验证的请求。

从桌面应用进行身份验证

本部分介绍如何使用桌面命令行对用户账号进行身份验证。

  1. 要允许开发者使用命令行访问您的应用,请创建桌面 OAuth 2.0 客户端 ID共享现有的桌面 OAuth 客户端 ID
  2. 将 OAuth 客户端 ID 列入许可名单,以便进行应用的程序化访问

登录应用

每位想要访问受 IAP 保护的应用的开发者都需要先登录。您可以将该过程打包到脚本中,例如使用 gcloud CLI。以下示例演示了如何使用 curl 登录并生成一个可用于访问应用的令牌:

  1. 登录有权访问 Google Cloud 资源的账号。
  2. 启动可回显传入请求的本地服务器。
        $ nc -k -l 4444
        
    注意:该命令使用 NetCat 实用程序。 您可以选择使用自己偏好的实用程序。
  3. 转到以下 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
  4. 在本地服务器输出中,查找请求参数。您应该会看到如下所示的内容: GET /?code=$CODE&scope=email%20openid%20https://www.googleapis.com/auth/userinfo.email&hd=google.com&prompt=consent HTTP/1.1 复制下面的代码以替换下面的 AUTH_CODE 以及桌面应用客户端 ID 和密钥:

    curl --verbose \
          --data client_id=DESKTOP_CLIENT_ID \
          --data client_secret=DESKTOP_CLIENT_SECRET \
          --data code=AUTH_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_IDDESKTOP_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 对象,您可以使用该字段来访问应用。

对服务帐号进行身份验证

您可以使用服务帐号 JWTOpenID Connect (OIDC) 令牌,通过 IAP 保护的资源对服务帐号进行身份验证。下表概述了不同身份验证令牌及其功能之间的一些差异。

Authentication 功能 服务账号 JWT OpenID Connect 令牌
情境感知访问权限支持
OAuth 2.0 客户端 ID 要求
令牌范围 受 IAP 保护的资源的网址 OAuth 2.0 客户端 ID

使用服务帐号 JWT 进行身份验证

使用 JWT 对服务帐号进行身份验证包括以下主要步骤:

  1. 向调用服务帐号授予 Service Account Token Creator 角色 (roles/iam.serviceAccountTokenCreator)。

    该角色向主账号授予创建短期有效凭据(如 JWT)的权限。

  2. 为受 IAP 保护的资源创建 JWT。

  3. 使用服务帐号私钥为 JWT 签名。

创建 JWT

创建的 JWT 应具有类似于以下示例的载荷:

{
  "iss": SERVICE_ACCOUNT_EMAIL_ADDRESS,
  "sub": SERVICE_ACCOUNT_EMAIL_ADDRESS,
  "aud": TARGET_URL,
  "iat": IAT,
  "exp": EXP,
}
  • 对于 isssub 字段,请指定服务帐号的电子邮件地址。它可以在服务帐号 JSON 文件的 client_email 字段中找到,也可以传入。典型格式:service-account@PROJECT_ID.iam.gserviceaccount.com

  • 对于 aud 字段,请指定受 IAP 保护的资源的网址。

  • 对于 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

  1. 运行以下命令以准备包含 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
    
  2. 使用以下 Google Cloud CLI 命令在 request.json 中为载荷签名:

    gcloud iam service-accounts sign-jwt --iam-account=SERVICE_ACCOUNT_EMAIL_ADDRESS claim.json output.jwt
    

    请求成功后,output.jwt 会包含一个已签名的 JWT。

  3. 使用 JWT 访问受 IAP 保护的资源。

Python

import datetime
import json

import google.auth
from google.cloud import iam_credentials_v1
import jwt

def generate_jwt_payload(service_account_email: str, resource_url: str) -> str:
  """Generates JWT payload for service account.

  The resource url provided must be the same as the url of the IAP secured resource.

  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:
    A signed-jwt that can be used to access IAP protected applications.
    Access the application with the JWT in the Authorization Header.
    curl --verbose --header 'Authorization: Bearer SIGNED_JWT' URL
  """
  iat = datetime.datetime.now(tz=datetime.timezone.utc)
  exp = iat + 3600
  return json.dumps({
      'iss': service_account_email,
      'sub': service_account_email,
      'aud': resource_url,
      'iat': iat,
      'exp': exp,
  })

def sign_jwt(target_sa: str, resource_url: str) -> str:
  """Signs JWT payload using ADC and IAM credentials API.

  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:
    A signed-jwt that can be used to access IAP protected apps.
  """
  source_credentials, _ = google.auth.default()
  iam_client = iam_credentials_v1.IAMCredentialsClient(credentials=source_credentials)
  return iam_client.sign_jwt(
      name=iam_client.service_account_path('-', target_sa),
      payload=generate_jwt_payload(target_sa, resource_url),
  ).signed_jwt

请求成功后,脚本将返回已签名的 JWT。使用 JWT 访问受 IAP 保护的资源。

curl

  1. 运行以下命令以准备包含 JWT 载荷的请求:

    cat << EOF > request.json
    {
      "payload": JWT_PAYLOAD
    }
    EOF
    
  2. 使用 IAM Service Account Credentials API 为 JWT 签名:

    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 将出现在响应中。

  3. 使用 JWT 访问受 IAP 保护的资源。

从本地凭据密钥文件对 JWT 进行签名

JWT 使用服务帐号的私钥进行签名。

如果您有服务帐号密钥文件,可以在本地对 JWT 进行签名。

该脚本会将 JWT 标头与载荷一起发送。对于标头中的 kid 字段,请使用服务帐号的私钥 ID,该 ID 位于服务帐号凭据 JSON 文件的 private_key_id 字段中。该密钥还可用于对 JWT 进行签名。

Python

import time
import jwt
import json

def generate_jwt_payload(service_account_email, resource_url):
  """Generates JWT payload for service account.

  The resource url provided must be the same as the url of the IAP secured resource.

  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:
    A signed-jwt that can be used to access IAP protected applications.
    Access the application with the JWT in the Authorization Header.
    curl --verbose --header 'Authorization: Bearer SIGNED_JWT' URL
  """
  iat = datetime.datetime.now(tz=datetime.timezone.utc)
  exp = iat + 3600
  return json.dumps({
      'iss': service_account_email,
      'sub': service_account_email,
      'aud': resource_url,
      'iat': iat,
      'exp': exp,
  })

def sign_jwt_with_key_file(credential_key_file_path, resource_url):
  """Signs JWT payload using local service account credential key file.

  Args:
    credential_key_file_path (str): Path to the downloaded JSON credentials of the service
      account the JWT is being created for.
    resource_url (str): Scope of JWT token, This is the url of the IAP protected application.
  Returns:
    A service account JWT created with a downloaded private key.
  """
  with open(credential_key_file_path, 'r') as credential_key_file:
      key_data = json.load(credential_key_file)

  PRIVATE_KEY_ID_FROM_JSON = key_data["private_key_id"]
  PRIVATE_KEY_FROM_JSON = key_data["private_key"]
  SERVICE_ACCOUNT_EMAIL = key_data["client_email"]

  # Sign JWT with private key and store key id in the header
  additional_headers = {'kid': PRIVATE_KEY_ID_FROM_JSON}
  payload = generate_jwt_payload(service_account_email=SERVICE_ACCOUNT_EMAIL, resource_url=resource_url)

  signed_jwt = jwt.encode(
      payload,
      PRIVATE_KEY_FROM_JSON,
      headers=additional_headers,
      algorithm='RS256',
  )
  return signed_jwt

结果为签名 JWT。

访问应用

在任何情况下,如需访问应用,请使用 signed-jwt,如下所示:

curl --verbose --header 'Authorization: Bearer SIGNED_JWT' URL

使用 OIDC 令牌进行身份验证

  1. 创建或使用现有的 OAuth 2.0 客户端 ID。要使用现有的 OAuth 2.0 客户端 ID,请按照如何共享 OAuth 客户端中的步骤操作。
  2. 将 OAuth 客户端 ID 列入许可名单,以便进行应用的程序化访问

您还需要将服务账号添加到受 IAP 保护的项目的访问列表中。以下代码示例显示了如何获取 OIDC 令牌。您必须在 Authorization: Bearer 标头中添加该令牌,才能向受 IAP 保护的资源发出身份验证请求。

获取默认服务账号的 OIDC 令牌

如果要为 Compute Engine、App Engine 或 Cloud Run 的默认服务帐号获取 OIDC 令牌,您可以使用以下代码示例生成令牌,以访问受 IAP 保护的资源:

C#


using Google.Apis.Auth.OAuth2;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;

public class IAPClient
{
    /// <summary>
    /// Makes a request to a IAP secured application by first obtaining
    /// an OIDC token.
    /// </summary>
    /// <param name="iapClientId">The client ID observed on 
    /// https://console.cloud.google.com/apis/credentials. </param>
    /// <param name="uri">HTTP URI to fetch.</param>
    /// <param name="cancellationToken">The token to propagate operation cancel notifications.</param>
    /// <returns>The HTTP response message.</returns>
    public async Task<HttpResponseMessage> InvokeRequestAsync(
        string iapClientId, string uri, CancellationToken cancellationToken = default)
    {
        // Get the OidcToken.
        // You only need to do this once in your application
        // as long as you can keep a reference to the returned OidcToken.
        OidcToken oidcToken = await GetOidcTokenAsync(iapClientId, cancellationToken);

        // Before making an HTTP request, always obtain the string token from the OIDC token,
        // the OIDC token will refresh the string token if it expires.
        string token = await oidcToken.GetAccessTokenAsync(cancellationToken);

        // Include the OIDC token in an Authorization: Bearer header to 
        // IAP-secured resource
        // Note: Normally you would use an HttpClientFactory to build the httpClient.
        // For simplicity we are building the HttpClient directly.
        using HttpClient httpClient = new HttpClient();
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
        return await httpClient.GetAsync(uri, cancellationToken);
    }

    /// <summary>
    /// Obtains an OIDC token for authentication an IAP request.
    /// </summary>
    /// <param name="iapClientId">The client ID observed on 
    /// https://console.cloud.google.com/apis/credentials. </param>
    /// <param name="cancellationToken">The token to propagate operation cancel notifications.</param>
    /// <returns>The HTTP response message.</returns>
    public async Task<OidcToken> GetOidcTokenAsync(string iapClientId, CancellationToken cancellationToken)
    {
        // Obtain the application default credentials.
        GoogleCredential credential = await GoogleCredential.GetApplicationDefaultAsync(cancellationToken);

        // Request an OIDC token for the Cloud IAP-secured client ID.
       return await credential.GetOidcTokenAsync(OidcTokenOptions.FromTargetAudience(iapClientId), cancellationToken);
    }
}

Go

如需向 IAP 进行身份验证,请设置应用默认凭据。如需了解详情,请参阅为本地开发环境设置身份验证

import (
	"context"
	"fmt"
	"io"
	"net/http"

	"google.golang.org/api/idtoken"
)

// makeIAPRequest makes a request to an application protected by Identity-Aware
// Proxy with the given audience.
func makeIAPRequest(w io.Writer, request *http.Request, audience string) error {
	// request, err := http.NewRequest("GET", "http://example.com", nil)
	// audience := "IAP_CLIENT_ID.apps.googleusercontent.com"
	ctx := context.Background()

	// client is a http.Client that automatically adds an "Authorization" header
	// to any requests made.
	client, err := idtoken.NewClient(ctx, audience)
	if err != nil {
		return fmt.Errorf("idtoken.NewClient: %w", err)
	}

	response, err := client.Do(request)
	if err != nil {
		return fmt.Errorf("client.Do: %w", err)
	}
	defer response.Body.Close()
	if _, err := io.Copy(w, response.Body); err != nil {
		return fmt.Errorf("io.Copy: %w", err)
	}

	return nil
}

Java


import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.auth.http.HttpCredentialsAdapter;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.auth.oauth2.IdTokenCredentials;
import com.google.auth.oauth2.IdTokenProvider;
import com.google.common.base.Preconditions;
import java.io.IOException;
import java.util.Collections;

public class BuildIapRequest {
  private static final String IAM_SCOPE = "https://www.googleapis.com/auth/iam";

  private static final HttpTransport httpTransport = new NetHttpTransport();

  private BuildIapRequest() {}

  private static IdTokenProvider getIdTokenProvider() throws IOException {
    GoogleCredentials credentials =
        GoogleCredentials.getApplicationDefault().createScoped(Collections.singleton(IAM_SCOPE));

    Preconditions.checkNotNull(credentials, "Expected to load credentials");
    Preconditions.checkState(
        credentials instanceof IdTokenProvider,
        String.format(
            "Expected credentials that can provide id tokens, got %s instead",
            credentials.getClass().getName()));

    return (IdTokenProvider) credentials;
  }

  /**
   * Clone request and add an IAP Bearer Authorization header with ID Token.
   *
   * @param request Request to add authorization header
   * @param iapClientId OAuth 2.0 client ID for IAP protected resource
   * @return Clone of request with Bearer style authorization header with ID Token.
   * @throws IOException exception creating ID Token
   */
  public static HttpRequest buildIapRequest(HttpRequest request, String iapClientId)
      throws IOException {

    IdTokenProvider idTokenProvider = getIdTokenProvider();
    IdTokenCredentials credentials =
        IdTokenCredentials.newBuilder()
            .setIdTokenProvider(idTokenProvider)
            .setTargetAudience(iapClientId)
            .build();

    HttpRequestInitializer httpRequestInitializer = new HttpCredentialsAdapter(credentials);

    return httpTransport
        .createRequestFactory(httpRequestInitializer)
        .buildRequest(request.getRequestMethod(), request.getUrl(), request.getContent());
  }
}

Node.js

/**
 * TODO(developer): Uncomment these variables before running the sample.
 */
// const url = 'https://some.iap.url';
// const targetAudience = 'IAP_CLIENT_ID.apps.googleusercontent.com';

const {GoogleAuth} = require('google-auth-library');
const auth = new GoogleAuth();

async function request() {
  console.info(`request IAP ${url} with target audience ${targetAudience}`);
  const client = await auth.getIdTokenClient(targetAudience);
  const res = await client.request({url});
  console.info(res.data);
}

request().catch(err => {
  console.error(err.message);
  process.exitCode = 1;
});

PHP

如需向 IAP 进行身份验证,请设置应用默认凭据。如需了解详情,请参阅为本地开发环境设置身份验证

namespace Google\Cloud\Samples\Iap;

# Imports Auth libraries and Guzzle HTTP libraries.
use Google\Auth\ApplicationDefaultCredentials;
use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;

/**
 * Make a request to an application protected by Identity-Aware Proxy.
 *
 * @param string $url The Identity-Aware Proxy-protected URL to fetch.
 * @param string $clientId The client ID used by Identity-Aware Proxy.
 */
function make_iap_request($url, $clientId)
{
    // create middleware, using the client ID as the target audience for IAP
    $middleware = ApplicationDefaultCredentials::getIdTokenMiddleware($clientId);
    $stack = HandlerStack::create();
    $stack->push($middleware);

    // create the HTTP client
    $client = new Client([
        'handler' => $stack,
        'auth' => 'google_auth'
    ]);

    // make the request
    $response = $client->get($url);
    print('Printing out response body:');
    print($response->getBody());
}

Python

如需向 IAP 进行身份验证,请设置应用默认凭据。如需了解详情,请参阅为本地开发环境设置身份验证

from google.auth.transport.requests import Request
from google.oauth2 import id_token
import requests


def make_iap_request(url, client_id, method="GET", **kwargs):
    """Makes a request to an application protected by Identity-Aware Proxy.

    Args:
      url: The Identity-Aware Proxy-protected URL to fetch.
      client_id: The client ID used by Identity-Aware Proxy.
      method: The request method to use
              ('GET', 'OPTIONS', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE')
      **kwargs: Any of the parameters defined for the request function:
                https://github.com/requests/requests/blob/master/requests/api.py
                If no timeout is provided, it is set to 90 by default.

    Returns:
      The page body, or raises an exception if the page couldn't be retrieved.
    """
    # Set the default timeout, if missing
    if "timeout" not in kwargs:
        kwargs["timeout"] = 90

    # Obtain an OpenID Connect (OIDC) token from metadata server or using service
    # account.
    open_id_connect_token = id_token.fetch_id_token(Request(), client_id)

    # Fetch the Identity-Aware Proxy-protected URL, including an
    # Authorization header containing "Bearer " followed by a
    # Google-issued OpenID Connect token for the service account.
    resp = requests.request(
        method,
        url,
        headers={"Authorization": "Bearer {}".format(open_id_connect_token)},
        **kwargs
    )
    if resp.status_code == 403:
        raise Exception(
            "Service account does not have permission to "
            "access the IAP-protected application."
        )
    elif resp.status_code != 200:
        raise Exception(
            "Bad response from application: {!r} / {!r} / {!r}".format(
                resp.status_code, resp.headers, resp.text
            )
        )
    else:
        return resp.text

Ruby

如需向 IAP 进行身份验证,请设置应用默认凭据。如需了解详情,请参阅为本地开发环境设置身份验证

# url = "The Identity-Aware Proxy-protected URL to fetch"
# client_id = "The client ID used by Identity-Aware Proxy"
require "googleauth"
require "faraday"

# The client ID as the target audience for IAP
id_token_creds = Google::Auth::Credentials.default target_audience: client_id

headers = {}
id_token_creds.client.apply! headers

resp = Faraday.get url, nil, headers

if resp.status == 200
  puts "X-Goog-Iap-Jwt-Assertion:"
  puts resp.body
else
  puts "Error requesting IAP"
  puts resp.status
  puts resp.headers
end

从本地服务账号密钥文件获取 OIDC 令牌

如果您有服务帐号密钥文件,则可以调整上述代码示例以提供服务帐号密钥文件。

Bash

  #!/usr/bin/env bash
  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}"

    local iam_scope="https://www.googleapis.com/auth/iam"
    local oauth_token_uri="https://www.googleapis.com/oauth2/v4/token"

    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')"
    local issued_at="$(date +%s)"
    local expires_at="$((issued_at + 600))"
    local header="{'alg':'RS256','typ':'JWT','kid':'${private_key_id}'}"
    local header_base64="$(echo "${header}" | base64)"
    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)"
    local signature_base64="$(printf %s "${header_base64}.${payload_base64}" | openssl dgst -binary -sha256 -sign <(printf '%s\n' "${private_key}")  | base64)"
    local assertion="${header_base64}.${payload_base64}.${signature_base64}"
    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)"
    local bearer_id_token="$(echo "${token_payload}" | jq -r '.id_token')"
    echo "${bearer_id_token}"
  }

  main(){
    # TODO: Replace the following variables:
    SERVICE_ACCOUNT_KEY="service_account_key_file_path"
    IAP_CLIENT_ID="iap_client_id"
    URL="application_url"

    # Obtain the ID token.
    ID_TOKEN=$(get_token "${SERVICE_ACCOUNT_KEY}" "${IAP_CLIENT_ID}")
    # Access the application with the ID token.
    curl --header "Authorization: Bearer ${ID_TOKEN}" "${URL}"
  }

  main "$@"

在所有其他情况下获取 OIDC 令牌

在所有其他情况下,请使用 IAM Credentials API 生成 OIDC 令牌,方法是在访问受 IAP 保护的资源之前模拟目标服务帐号。此过程涉及以下步骤:

  1. 为调用服务帐号(与获取 ID 令牌的代码关联的服务帐号)提供 Service Account OpenID Connect Identity Token Creator 角色 (roles/iam.serviceAccountOpenIdTokenCreator)。

    这将使调用服务帐号能够模拟目标服务帐号。

  2. 使用调用服务帐号提供的凭据对目标服务帐号调用 generateIdToken 方法。

    audience 字段设置为您的客户端 ID。

如需查看分步说明,请参阅创建 ID 令牌

从 Proxy-Authorization 标头进行身份验证

如果您的应用使用 Authorization 请求标头,您可以改为在 Proxy-Authorization: Bearer 标头中包含 ID 令牌。如果在 Proxy-Authorization 标头中找到了有效的 ID 令牌,则 IAP 会用它授权请求。授权请求后,IAP 会将 Authorization 标头传递给您的应用,而不处理内容。

如果在 Proxy-Authorization 标头中未找到有效的 ID 令牌,则 IAP 会继续处理 Authorization 标头并在将请求传递给应用之前去除 Proxy-Authorization 标头。

后续步骤