获取 ID 令牌

本页面介绍了用于获取 Google 签名的 OpenID Connect (OIDC) ID 令牌的一些方法。您需要在以下身份验证使用场景中使用 Google 签名的 ID 令牌:

如需了解 ID 令牌的内容和有效期,请参阅 ID 令牌

ID 令牌具有其可用于的特定服务或应用,由其 aud 声明的值指定。本页面使用“目标服务”一词来指代可使用 ID 令牌向其进行身份验证的服务或应用。

获取 ID 令牌后,您可以将其添加到对目标服务的请求的 Authorization 标头中。

获取 ID 令牌的方法

获取 ID 令牌的方法有多种。本页介绍了以下几种方法:

Cloud Run 和 Cloud Functions 提供特定于服务的方法来获取 ID 令牌。如需了解详情,请参阅向 Cloud Run 或 Cloud Functions 上托管的应用进行身份验证

如果您需要 ID 令牌被不在 Google Cloud 上托管的应用接受,则或许可以使用这些方法,但您应该确定应用所需的 ID 令牌声明。

从元数据服务器获取 ID 令牌

如果您的代码在可以关联服务账号的资源上运行,所关联服务的元数据服务器在大多数情况下都可以提供 ID 令牌。元数据服务器会为关联的服务账号生成 ID 令牌。您无法从元数据服务器获取基于用户凭据的 ID 令牌。

您的代码在以下 Google Cloud 服务上运行时,您可以从元数据服务器获取 ID 令牌:

如需从元数据服务器检索 ID 令牌,您需要查询服务账号的身份端点,如以下示例所示。

curl

AUDIENCE 替换为目标服务的 URI,例如 http://www.example.com

curl -H "Metadata-Flavor: Google" \
  'http://metadata/computeMetadata/v1/instance/service-accounts/default/identity?audience=AUDIENCE'

PowerShell

AUDIENCE 替换为目标服务的 URI,例如 http://www.example.com

$value = (Invoke-RestMethod `
  -Headers @{'Metadata-Flavor' = 'Google'} `
  -Uri "http://metadata/computeMetadata/v1/instance/service-accounts/default/identity?audience=AUDIENCE")
$value

Java

如需运行此代码示例,您必须安装 Java 版 Google API 客户端库


import com.google.auth.oauth2.GoogleCredentials;
import com.google.auth.oauth2.IdTokenCredentials;
import com.google.auth.oauth2.IdTokenProvider;
import com.google.auth.oauth2.IdTokenProvider.Option;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.Arrays;

public class IdTokenFromMetadataServer {

  public static void main(String[] args) throws IOException, GeneralSecurityException {
    // TODO(Developer): Replace the below variables before running the code.

    // The url or target audience to obtain the ID token for.
    String url = "https://example.com";

    getIdTokenFromMetadataServer(url);
  }

  // Use the Google Cloud metadata server to create an identity token and add it to the
  // HTTP request as part of an Authorization header.
  public static void getIdTokenFromMetadataServer(String url) throws IOException {
    // Construct the GoogleCredentials object which obtains the default configuration from your
    // working environment.
    GoogleCredentials googleCredentials = GoogleCredentials.getApplicationDefault();

    IdTokenCredentials idTokenCredentials =
        IdTokenCredentials.newBuilder()
            .setIdTokenProvider((IdTokenProvider) googleCredentials)
            .setTargetAudience(url)
            // Setting the ID token options.
            .setOptions(Arrays.asList(Option.FORMAT_FULL, Option.LICENSES_TRUE))
            .build();

    // Get the ID token.
    // Once you've obtained the ID token, you can use it to make an authenticated call to the
    // target audience.
    String idToken = idTokenCredentials.refreshAccessToken().getTokenValue();
    System.out.println("Generated ID token.");
  }
}

Go

import (
	"context"
	"fmt"
	"io"

	"golang.org/x/oauth2/google"
	"google.golang.org/api/idtoken"
	"google.golang.org/api/option"
)

// getIdTokenFromMetadataServer uses the Google Cloud metadata server environment
// to create an identity token and add it to the HTTP request as part of an Authorization header.
func getIdTokenFromMetadataServer(w io.Writer, url string) error {
	// url := "http://www.example.com"

	ctx := context.Background()

	// Construct the GoogleCredentials object which obtains the default configuration from your
	// working environment.
	credentials, err := google.FindDefaultCredentials(ctx)
	if err != nil {
		return fmt.Errorf("failed to generate default credentials: %w", err)
	}

	ts, err := idtoken.NewTokenSource(ctx, url, option.WithCredentials(credentials))
	if err != nil {
		return fmt.Errorf("failed to create NewTokenSource: %w", err)
	}

	// Get the ID token.
	// Once you've obtained the ID token, you can use it to make an authenticated call
	// to the target audience.
	_, err = ts.Token()
	if err != nil {
		return fmt.Errorf("failed to receive token: %w", err)
	}
	fmt.Fprintf(w, "Generated ID token.\n")

	return nil
}

Node.js

/**
 * TODO(developer):
 *  1. Uncomment and replace these variables before running the sample.
 */
// const targetAudience = 'http://www.example.com';

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

async function getIdTokenFromMetadataServer() {
  const googleAuth = new GoogleAuth();

  const client = await googleAuth.getIdTokenClient(targetAudience);

  // Get the ID token.
  // Once you've obtained the ID token, you can use it to make an authenticated call
  // to the target audience.
  await client.idTokenProvider.fetchIdToken(targetAudience);
  console.log('Generated ID token.');
}

getIdTokenFromMetadataServer();

Python

如需运行此代码示例,您必须安装 Python 版 Google 身份验证库


import google
import google.oauth2.credentials
from google.auth import compute_engine
import google.auth.transport.requests

def idtoken_from_metadata_server(url: str):
    """
    Use the Google Cloud metadata server in the Cloud Run (or AppEngine or Kubernetes etc.,)
    environment to create an identity token and add it to the HTTP request as part of an
    Authorization header.

    Args:
        url: The url or target audience to obtain the ID token for.
            Examples: http://www.example.com
    """

    request = google.auth.transport.requests.Request()
    # Set the target audience.
    # Setting "use_metadata_identity_endpoint" to "True" will make the request use the default application
    # credentials. Optionally, you can also specify a specific service account to use by mentioning
    # the service_account_email.
    credentials = compute_engine.IDTokenCredentials(
        request=request, target_audience=url, use_metadata_identity_endpoint=True
    )

    # Get the ID token.
    # Once you've obtained the ID token, use it to make an authenticated call
    # to the target audience.
    credentials.refresh(request)
    # print(credentials.token)
    print("Generated ID token.")

Ruby

如需运行此代码示例,您必须安装 Ruby 版 Google 身份验证库

require "googleauth"

##
# Uses the Google Cloud metadata server environment to create an identity token
# and add it to the HTTP request as part of an Authorization header.
#
# @param url [String] The url or target audience to obtain the ID token for
#   (e.g. "http://www.example.com")
#
def auth_cloud_idtoken_metadata_server url:
  # Create the GCECredentials client.
  id_client = Google::Auth::GCECredentials.new target_audience: url

  # Get the ID token.
  # Once you've obtained the ID token, you can use it to make an authenticated call
  # to the target audience.
  id_client.fetch_access_token
  puts "Generated ID token."

  id_client.refresh!
end

使用连接服务生成 ID 令牌

某些 Google Cloud 服务可帮助您调用其他服务。您可以借助这些连接服务来确定何时需进行调用或管理涉及调用服务的工作流。以下服务在调用需要 ID 令牌的服务时,会自动添加 ID 令牌,并包含相应的 aud 声明值:

Cloud Scheduler
Cloud Scheduler 是一项全代管式企业级 cron 作业调度服务。您可以将 Cloud Scheduler 配置为在调用其他服务时添加 ID 令牌或访问令牌。如需了解详情,请参阅对 HTTP 目标使用身份验证
Cloud Tasks
借助 Tasks,您可以管理分布式任务的执行。您可以将任务配置为在调用服务时添加 ID 令牌或访问令牌。如需了解详情,请参阅将 HTTP 目标任务与身份验证令牌配合使用
Pub/Sub
Pub/Sub 支持服务之间的异步通信。您可以将 Pub/Sub 配置为在消息中包含 ID 令牌。如需了解详情,请参阅推送订阅身份验证
Workflows
Workflows 是一个全代管式编排平台,该平台会按照您定义的顺序执行服务:工作流。您可以定义工作流,以便在调用其他服务时添加 ID 令牌或访问令牌。如需了解详情,请参阅通过工作流发出经过身份验证的请求

通过模拟服务账号生成 ID 令牌

借助服务账号模拟,主账号可为可信服务账号生成短期有效凭据。然后,主账号可以使用这些凭据以服务账号的身份进行身份验证。

主账号必须对服务账号具有可启用模拟的 IAM 角色,才能模拟此服务账号。如果主账号本身是另一个服务账号,则只需直接向该服务账号提供所需的权限并使其模拟自身可能看起来更加容易。此配置(称为自模拟)会造成安全漏洞,因为它会让服务账号创建可以永久刷新的访问令牌。

服务账号模拟应始终涉及两个主账号:代表调用方的主账号,以及被模拟的服务账号(称为具有权限的服务账号)。

如需通过模拟服务账号生成 ID 令牌,请使用以下常规过程。

如需了解分步说明,请参阅创建 ID 令牌

  1. 确定或创建服务账号,使其成为具有权限的服务账号。为该服务账号授予目标服务所需的 IAM 角色:

    • 对于 Cloud Run 服务,请授予 Cloud Run Invoker 角色 (roles/run.invoker)。
    • 对于 Cloud Functions,请授予 Cloud Functions Invoker 角色 (roles/cloudfunctions.invoker)。
    • 如需了解其他目标服务,请参阅相应服务的产品文档。
  2. 确定将执行模拟的主账号,并设置应用默认凭据 (ADC) 以使用此主账号的凭据。

    对于开发环境,主账号通常是您使用 gcloud CLI 提供给 ADC 的用户账号。但是,如果您在关联有服务账号的资源上运行,则关联的服务账号是主账号。

  3. 向主账号授予 Service Account OpenID Connect Identity Token Creator 角色 (roles/iam.serviceAccountOpenIdTokenCreator)。

  4. 使用 IAM Credentials API 为已获授权的服务账号生成 ID 令牌。

生成通用 ID 令牌,以使用 Cloud Run 和 Cloud Functions 进行开发

您可以使用 gcloud CLI 获取用户凭据的 ID 令牌,对于调用方具有调用所需 IAM 权限的任何 Cloud Run 服务或 Cloud Functions 函数,该令牌均可与其搭配使用。此令牌将无法用于其他任何应用。

使用外部身份提供方生成 ID 令牌

使用外部身份提供方生成 ID 令牌使用的是工作负载身份联合,让您可以设置 Google Cloud 与外部身份提供方之间的关系。然后,您可以使用外部身份提供方提供的凭据生成可在 Google Cloud 中使用的 ID 令牌或访问令牌。

如需为外部身份提供方提供的凭据生成 ID 令牌,请按照以下步骤操作:

  1. 确定或创建服务账号,以提供调用目标服务所需的 IAM 角色。

    最佳实践是专门为此目的创建一个服务账号,并为其只提供所需的角色。此方法遵循最小权限原则。

  2. 确定调用目标服务所需的角色。向目标服务上的服务账号授予以下角色:

    • 对于 Cloud Run 服务,请授予 Cloud Run Invoker 角色 (roles/run.invoker)。
    • 对于 Cloud Functions,请授予 Cloud Functions Invoker 角色 (roles/cloudfunctions.invoker)。
    • 如需了解其他目标服务,请参阅相应服务的产品文档。
  3. 按照配置工作负载身份联合所述,为您的身份提供方配置工作负载身份联合。

  4. 按照授予外部身份模拟服务账号的权限中的说明执行操作。将您在上述步骤中设置的服务账号用作要模拟的服务账号。

  5. 使用 REST API 获取短期有效的令牌,但对于最后一步,请改用 generateIdToken 方法获取 ID 令牌:

    Bash

    ID_TOKEN=$(curl -0 -X POST https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/SERVICE_ACCOUNT_EMAIL:generateIdToken \
        -H "Content-Type: text/json; charset=utf-8" \
        -H "Authorization: Bearer $STS_TOKEN" \
        -d @- <<EOF | jq -r .token
        {
            "audience": "AUDIENCE"
        }
    EOF
    )
    echo $ID_TOKEN
    

    PowerShell

    $IdToken = (Invoke-RestMethod `
        -Method POST `
        -Uri "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/SERVICE_ACCOUNT_EMAIL:generateIdToken" `
        -Headers @{ "Authorization" = "Bearer $StsToken" } `
        -ContentType "application/json" `
        -Body (@{
            "audience" = "AUDIENCE"
        } | ConvertTo-Json)).token
    Write-Host $IdToken
    

    请替换以下内容:

    • SERVICE_ACCOUNT_EMAIL:服务账号的电子邮件地址
    • AUDIENCE:该令牌的受众群体,例如使用该令牌访问的应用或服务

后续步骤