服务之间的身份验证
除了对最终用户请求进行身份验证之外,您可能还需要对向 API 发出请求的服务(非真人用户)进行身份验证。 本页面介绍如何使用服务账号为真人或服务提供身份验证。
概览
要识别向您的 API 发送请求的服务,请使用服务账号。 调用服务会使用服务账号的私钥来签署安全的 JSON Web 令牌 (JWT),并将已签名的 JWT 随请求发送到您的 API。
要在您的 API 和调用服务中实现服务账号身份验证,请执行以下操作:
- 为调用的服务创建服务账号和密钥。
- 在 API Gateway 服务的 API 配置中添加对身份验证的支持。
将代码添加到调用服务:
- 创建 JWT 并使用服务账号的私钥为其签名。
- 将签名的 JWT 随请求发送到 API。
API Gateway 会在将请求转发给您的 API 之前验证 JWT 中的声明是否与 API 配置中的配置相匹配。API Gateway 不会检查您已经在服务账号上授予的 Cloud Identity 权限。
前提条件
本页面假定您已经完成以下操作:
使用密钥创建服务账号
您需要一个包含调用服务用于签署 JWT 的私钥文件的服务账号。如果有多个服务向您的 API 发送请求,您可以创建一个服务账号来代表所有调用服务。如果您需要区分这些服务(例如,它们可能具有不同的权限),您可以为每个调用服务分别创建服务账号和密钥。
本部分介绍如何使用 Google Cloud 控制台和 gcloud
命令行工具来创建服务账号和私钥文件,以及为服务账号分配 Service Account Token Creator 角色。如需了解如何使用 API 执行此任务,请参阅创建和管理服务账号。
要使用密钥创建服务账号:
Google Cloud 控制台
创建服务账号:
在 Google Cloud 控制台中,前往创建服务账号。
选择一个项目。
在服务账号名称字段中,输入一个名称。Google Cloud 控制台会根据此名称填充服务账号 ID 字段。
可选:在服务账号说明字段中,输入说明。
点击创建。
点击选择角色字段。
在所有角色下,选择服务账号 > Service Account Token Creator。
点击继续。
点击完成以完成服务账号的创建过程。
不要关闭浏览器窗口。您将在下一步骤中用到它。
创建服务账号密钥:
- 在 Google Cloud 控制台中,点击您创建的服务账号的电子邮件地址。
- 点击密钥。
- 依次点击添加密钥和创建新密钥。
- 点击创建。JSON 密钥文件将下载到您的计算机上。
- 点击关闭。
gcloud
您可以使用本地机器上的 Google Cloud CLI 或在 Cloud Shell 中运行以下命令。
设置
gcloud
的默认账号。如果您有多个账号,请务必选择您要使用的 Google Cloud 项目中的账号。gcloud auth login
显示您的 Google Cloud 项目的 ID:
gcloud projects list
设置默认项目。将
PROJECT_ID
替换为您要使用的 Google Cloud 项目 ID。gcloud config set project PROJECT_ID
创建一个服务账号。将
SA_NAME
和SA_DISPLAY_NAME
替换为您要使用的名称和显示名。gcloud iam service-accounts create SA_NAME \ --display-name "SA_DISPLAY_NAME"
显示刚刚创建的服务账号的电子邮件地址。
gcloud iam service-accounts list
添加 Service Account Token Creator 角色。将
SA_EMAIL_ADDRESS
替换为服务账号的电子邮件地址。gcloud projects add-iam-policy-binding PROJECT_ID \ --member serviceAccount:SA_EMAIL_ADDRESS \ --role roles/iam.serviceAccountTokenCreator
在当前工作目录中创建服务账号密钥文件。 将
FILE_NAME
替换为您要用于密钥文件的名称。默认情况下,gcloud
命令会创建一个 JSON 文件。gcloud iam service-accounts keys create FILE_NAME.json \ --iam-account SA_EMAIL_ADDRESS
如需详细了解上述命令,请参阅 gcloud
参考。
如需了解如何对私钥采取保护措施,请参阅管理凭据的最佳做法。
配置 API 以支持身份验证
为网关创建 API 配置时,您需要指定网关用来与其他服务交互的服务账号。 为服务启用服务账号身份验证调用修改网关安全要求对象和安全定义对象。按照以下步骤操作后,API Gateway 可以验证调用服务使用的已签名 JWT 中的声明。
在 API 配置中添加服务账号作为颁发者。
securityDefinitions: DEFINITION_NAME: authorizationUrl: "" flow: "implicit" type: "oauth2" x-google-issuer: "SA_EMAIL_ADDRESS" x-google-jwks_uri: "https://www.googleapis.com/robot/v1/metadata/x509/SA_EMAIL_ADDRESS"
- 将
DEFINITION_NAME
替换为标识此安全性定义的字符串。您可能希望将其替换为服务账号名称或标识调用服务的名称。 - 将
SA_EMAIL_ADDRESS
替换为服务账号的电子邮件地址。 - 您可以在 API 配置中定义多个安全定义,但每个定义必须具有不同的
x-google-issuer
。如果您为每个调用服务创建了单独的服务账号,那么您可以为每个服务账号创建安全性定义,例如:
securityDefinitions: service-1: authorizationUrl: "" flow: "implicit" type: "oauth2" x-google-issuer: "service-1@example-project-12345.iam.gserviceaccount.com" x-google-jwks_uri: "https://www.googleapis.com/robot/v1/metadata/x509/service-1@example-project-12345.iam.gserviceaccount.com" service-2: authorizationUrl: "" flow: "implicit" type: "oauth2" x-google-issuer: "service-2@example-project-12345.iam.gserviceaccount.com" x-google-jwks_uri: "https://www.googleapis.com/robot/v1/metadata/x509/service-2@example-project-12345.iam.gserviceaccount.com"
- 将
您可以选择将
x-google-audiences
添加到securityDefinitions
部分。如果您未添加x-google-audiences
,则 API Gateway 要求 JWT 中的"aud"
(受众群体)声明的格式为https://SERVICE_NAME
,其中 SERVICE_NAME 是 API 网关服务的名称,您已在 OpenAPI 文档的host
字段中配置该服务。在文件的顶层位置添加
security
部分(不缩进或嵌套)以应用于整个 API,或者在方法级层添加以应用于特定方法。如果同时在 API 级层和方法级层使用security
部分,则方法级层的设置将替换 API 级层的设置。security: - DEFINITION_NAME: []
- 将
DEFINITION_NAME
替换为您在securityDefinitions
部分中使用的名称。 如果您在
securityDefinitions
部分有多个定义,请将它们添加到security
部分,例如:security: - service-1: [] - service-2: []
- 将
部署更新后的 API 配置。
在 API Gateway 将请求转发到 API 之前,API Gateway 会验证以下几个方面:
- 使用公钥来验证 JWT 的签名,该签名位于 API 配置的
x-google-jwks_uri
字段中指定的 URI 处。 - 验证 JWT 中的
"iss"
(颁发者)声明与x-google-issuer
字段中指定的值是否匹配。 - 验证 JWT 中的
"aud"
(目标对象)声明是否包含您的 API Gateway 服务名称或与您在x-google-audiences
字段中指定的任一值匹配。 - 使用
"exp"
(到期时间)声明来验证令牌是否未到期。
如需详细了解 x-google-issuer
、x-google-jwks_uri
和 x-google-audiences
,请参阅 OpenAPI 扩展程序。
向 API Gateway API 发出经过身份验证的请求
要发送经过身份验证的请求,调用服务会发送用您在 API 配置中指定的服务账号签名的 JWT。调用服务必须:
- 创建 JWT 并使用服务账号的私钥对其进行签名。
- 将签名的 JWT 随请求发送到 API。
以下示例代码演示了此过程如何选取语言。如要使用其他语言发出经过身份验证的请求,请参阅 jwt.io 以获取支持的库列表。
- 在调用服务中,添加以下函数并将以下参数传递给它:
Java saKeyfile
:服务账号私钥文件的完整路径。-
saEmail
:服务账号的电子邮件地址。 -
audience
:如果您将x-google-audiences
字段添加到 API 配置,请将audience
设置为您为x-google-audiences
指定的值之一。否则,请将audience
设置为https://SERVICE_NAME
,其中SERVICE_NAME
是您的 API Gateway 服务名称。 -
expiryLength
:JWT 的到期时间,以秒为单位。
Python -
sa_keyfile
:服务账号私钥文件的完整路径。 -
sa_email
:服务账号的电子邮件地址。 -
audience
:如果您将x-google-audiences
字段添加到 API 配置,请将audience
设置为您为x-google-audiences
指定的值之一。否则,请将audience
设置为https://SERVICE_NAME
,其中SERVICE_NAME
是您的 API Gateway 服务名称。 -
expiry_length
:JWT 的到期时间,以秒为单位。
Go saKeyfile
:服务账号私钥文件的完整路径。-
saEmail
:服务账号的电子邮件地址。 -
audience
:如果您将x-google-audiences
字段添加到 API 配置,请将audience
设置为您为x-google-audiences
指定的值之一。否则,请将audience
设置为https://SERVICE_NAME
,其中SERVICE_NAME
是您的 API Gateway 服务名称。 -
expiryLength
:JWT 的到期时间,以秒为单位。
该函数会创建一个 JWT,使用私钥文件对其进行签名,并返回已签名的 JWT。
Java Python Go - 在调用服务中,添加以下函数,将签名的 JWT 随请求的
Authorization: Bearer
标头发送到 API:Java Python Go
当您使用 JWT 发送请求时,出于安全原因,我们建议您将身份验证令牌放在 Authorization: Bearer
标头中。例如:
curl --request POST \ --header "Authorization: Bearer ${TOKEN}" \ "${GATEWAY_URL}/echo"
其中 GATEWAY_URL
和 TOKEN
分别是包含已部署网关网址和身份验证令牌的环境变量。
在 API 中接收经过验证的结果
API Gateway 通常会转发它收到的所有标头。但是,当后端地址由 API 配置中的 x-google-backend
指定时,它会替换原来的 Authorization
标头。
API Gateway 会将 X-Apigateway-Api-Userinfo
中的身份验证结果发送到后端 API。我们建议您使用此标头,而不是原来的 Authorization
标头。此标头采用 base64url
编码,并且包含 JWT 载荷。