当在 Python 2 运行时中运行的应用向另一个 App Engine 应用发送请求时,它可以使用 App Engine App Identity API 来声明其身份。接收请求的应用可以使用此身份来确定是否应处理该请求。
如果您的 Python 3 应用在向其他 App Engine 应用发送请求时需要声明其身份,则您可以使用由 Google 的 OAuth 2.0 API 颁发并解码的 OpenID Connect (OIDC) ID 令牌。
下文概述了如何使用 OIDC ID 令牌来声明和验证身份:
- 名为“应用 A”的 App Engine 应用从 Google Cloud 运行时环境检索 ID 令牌。
- 应用 A 在向应用 B(它是另一个 App Engine 应用)发送请求之前,会先在请求标头中添加此令牌。
- 应用 B 使用 Google 的 OAuth 2.0 API 来验证令牌载荷。解码后的载荷包含应用 A 经过验证的身份,其采用应用 A 的默认服务帐号的电子邮件地址格式。
- 应用 B 将载荷中的身份与允许响应的身份列表进行比较。如果请求来自允许的应用,则应用 B 会处理该请求并做出响应。
本指南介绍了如何更新 App Engine 应用以便使用 OpenID Connect (OIDC) ID 令牌来声明身份,以及如何更新其他 App Engine 应用以便在处理请求之前先使用 ID 令牌来验证身份。
App Identity API 和 OIDC API 之间的主要区别
Python 2 运行时版本的应用无需明确声明身份。当应用使用
httplib
、urllib
或urllib2
Python 库或 App Engine URL Fetch 服务来发送出站请求时,运行时使用 App Engine URL Fetch 服务发出请求。如果请求正在发送至appspot.com
网域,则 URL Fetch 会在请求中添加X-Appengine-Inbound-Appid
标头,以自动声明发出请求的应用的身份。该标头包含应用的 ID(也称为项目 ID)。Python 3 运行时版本的应用确实需要明确声明身份,方法是从 Google Cloud 运行时环境检索 OIDC ID 令牌并将其添加到请求标头中。您需要更新向其他 App Engine 应用发送请求的所有代码,以便请求包含 OIDC ID 令牌。
请求中的
X-Appengine-Inbound-Appid
标头包含发送请求的应用的项目 ID。Google OIDC ID 令牌的载荷并不会直接标识应用本身的项目 ID。相反,该令牌会提供此服务帐号的电子邮件地址,以标识运行该应用的服务帐号。您需要添加一些代码,以从令牌载荷中提取用户名。
如果该服务帐号是项目的默认 App Engine 服务帐号,则您可以在服务帐号的电子邮件地址中找到项目 ID。此地址的用户名部分与项目 ID 相同。在这种情况下,接收方应用代码可在其允许发来请求的项目 ID 列表中查找。
但是,如果请求方应用使用的是用户管理的服务帐号,而不是默认 App Engine 服务帐号,则接收方应用可以仅验证该服务帐号的身份,这不一定会定义请求方应用的项目 ID。 在这种情况下,接收方应用必须维护一个允许的服务帐号电子邮件地址列表,而不是允许的项目 ID 列表。
URL Fetch API 调用的配额与用于授予令牌的 Google 的 OAuth 2.0 API 配额不同。您可以在 Google Cloud 控制台 OAuth 同意屏幕中查看您每天可以授予的令牌数量上限。URL Fetch(即 App Identity API)和 Google 的 OAuth 2.0 API 都不会产生费用。
迁移过程概览
如需迁移 Python 应用以使用 OIDC API 声明和验证身份,请执行以下操作:
在向其他 App Engine 应用发送请求时需要声明身份的应用中:
等待直至您的应用在 Python 3 环境中运行以迁移到 ID 令牌。
尽管在 Python 2 运行时中可以使用 ID 令牌,但 Python 2 中的步骤非常复杂,只有在更新应用以在 Python 3 运行时中运行时才暂时需要执行这些步骤。
当应用在 Python 3 中运行之后,请更新应用以请求 ID 令牌并将该令牌添加到请求标头中。
在处理请求之前需要验证身份的应用中:
首先升级 Python 2 应用以便支持 ID 令牌和 App Identity API 身份。这样一来,您的应用就能够验证并处理来自使用 App Identity API 的 Python 2 应用或使用 ID 令牌的 Python 3 应用的请求。
升级后的 Python 2 应用稳定之后,请将它们迁移至 Python 3 运行时中。继续支持 ID 令牌和 App Identity API 身份,直至确定应用不再需要支持来自旧版应用的请求。
如果您不再需要处理来自旧版 App Engine 应用的请求,请移除用于验证 App Identity API 身份的代码。
测试应用之后,请先部署用于处理请求的应用。然后部署更新后的 Python 3 应用,该应用使用 ID 令牌来声明身份。
声明身份
等待直到您的应用在 Python 3 环境中运行,然后按照以下步骤操作来升级应用,以使用 ID 令牌声明身份:
为 Python 3 应用安装 google-auth
客户端库
如需将 google-auth
客户端库提供给 Python3 应用,请在 app.yaml
文件所在的文件夹中创建一个 requirements.txt
文件,并添加以下行:
google-auth
部署应用时,App Engine 将下载 requirements.txt
文件中定义的所有依赖项。
对于本地开发,我们建议您在虚拟环境(例如 venv)中安装依赖项。
添加代码以声明身份
搜索您的代码并查找所有向其他 App Engine 应用发送请求的实例。请先更新上述实例以执行以下操作,然后再发送请求:
添加以下 import 命令:
from google.auth.transport import requests as reqs from google.oauth2 import id_token
使用
google.oauth2.id_token.fetch_id_token(request, audience)
检索 ID 令牌。在方法调用中添加下列参数:request
:传递您准备发送的请求对象。audience
:传递您要将请求发送到的应用的网址。这样可以将令牌绑定到请求并防止其他应用使用该令牌。为清楚明确起见,我们建议您传递 App Engine 为接收请求的特定服务创建的
appspot.com
网址,即使您对应用使用自定义网域也是如此。
在请求对象中,设置以下标头:
'Authorization': 'ID {}'.format(token)
例如:
测试用于声明身份的更新
如需在本地运行您的应用并测试应用是否能够成功发送 ID 令牌,请执行以下操作:
请按照以下步骤在本地环境中提供默认 App Engine 服务帐号的凭据(Google OAuth API 需要这些凭据才能生成 ID 令牌):
输入以下
gcloud
命令以针对项目的默认 App Engine 帐号检索服务帐号密钥:gcloud iam service-accounts keys create ~/key.json --iam-account project-ID@appspot.gserviceaccount.com
将 project-ID 替换为您的 Google Cloud 项目的 ID。
现在,服务帐号密钥文件已下载到您的机器上。您可以根据需要移动并重命名此文件。务必要安全存储此文件,因为它能够以服务帐号的身份进行身份验证。如果丢失了该文件,或者该文件向未授权的用户公开了,请删除服务帐号密钥,然后创建一个新密钥。
输入以下命令:
<code>export GOOGLE_APPLICATION_CREDENTIALS=<var>service-account-key</var></code>
将 service-account-key 替换为包含所下载服务帐号密钥的文件的绝对路径名。
在您导出
GOOGLE_APPLICATION_CREDENTIALS
环境变量的同一 shell 中,启动 Python 应用。从应用发送请求并确认操作是否成功。如果您还没有可以接收请求并使用 ID 令牌来验证身份的应用,请执行以下操作:
验证和处理请求
如需升级 Python 2 应用以便在处理请求之前先使用 ID 令牌或 App Identity API 身份,请执行以下操作:
安装 google-auth 客户端库。
更新代码以便执行以下操作:
如果请求中包含
X-Appengine-Inbound-Appid
标头,请使用该标头验证身份。在旧版运行时(如 Python 2)中运行的应用将包含此标头。如果请求不包含
X-Appengine-Inbound-Appid
标头,请检查是否存在 OIDC ID 令牌。如果该令牌存在,请验证令牌载荷并检查发送者的身份。
测试您的更新。
为 Python 2 应用安装 google-auth 客户端库
如需使 Python 2 应用能够使用 google-auth
客户端库,请执行以下操作:
在
app.yaml
文件所在的文件夹中创建requirements.txt
文件,并添加以下行:google-auth==1.19.2
我们建议您使用 1.19.2 版的 Cloud Logging 客户端库,因为它支持 Python 2.7 应用。
在应用的
app.yaml
文件的libraries
部分中,指定 SSL 库(如果尚未指定的话):libraries: - name: ssl version: latest
创建一个用于存储第三方库的目录,如
lib/
。然后使用pip install
将库安装到该目录中。 例如:pip install -t lib -r requirements.txt
在
app.yaml
文件所在的文件夹中创建appengine_config.py
文件。将以下内容添加到appengine_config.py
文件:# appengine_config.py import pkg_resources from google.appengine.ext import vendor # Set path to your libraries folder. path = 'lib' # Add libraries installed in the path folder. vendor.add(path) # Add libraries to pkg_resources working set to find the distribution. pkg_resources.working_set.add_entry(path)
上例中的
appengine_config.py
文件假定lib
文件夹位于当前工作目录中。如果您无法保证lib
始终位于当前工作目录中,请指定lib
文件夹的完整路径。例如:import os path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'lib')
对于本地开发,我们建议您在虚拟环境(如 Python 2 的 virtualenv)中安装依赖项。
更新用于验证请求的代码
搜索您的代码并查找所有获取 X-Appengine-Inbound-Appid
标头值的实例。更新上述实例以执行以下操作:
添加以下 import 命令:
from google.auth.transport import requests as reqs from google.oauth2 import id_token
如果传入的请求不包含
X-Appengine-Inbound-Appid
标头,请查找Authorization
标头并检索其值。标头值的格式为“ID: token”。
使用
google.oauth2.id_token.verify_oauth2_token(token, request, audience)
验证并检索解码后的令牌载荷。在方法调用中添加下列参数:token
:传递您从传入的请求中提取的令牌。request
:传递新的google.auth.transport.Request
对象。audience
:传递当前应用(即正在发送验证请求的应用)的网址。Google 的授权服务器会将此网址与最初生成令牌时提供的网址进行比较。如果网址不匹配,则令牌将无法通过验证,而授权服务器将返回错误。
verify_oauth2_token
方法会返回解码后的令牌载荷,其中包含多个名称/值对,包括生成该令牌的应用的默认服务帐号的电子邮件地址。从令牌载荷的电子邮件地址中提取用户名。
用户名与发送请求的应用的项目 ID 相同。此值与之前在
X-Appengine-Inbound-Appid
标头中返回的值相同。如果用户名/项目 ID 位于允许的项目 ID 列表中,请处理请求。
例如:
测试用于验证身份的更新
如需测试应用是否能够使用 ID 令牌或 X-Appengine-Inbound-Appid
标头来验证请求,请在 Python 2 本地开发服务器中运行应用,然后从 Python 2 应用(它将使用 App Identity API)和发送 ID 令牌的 Python 3 应用发送请求。
如果您尚未更新应用以发送 ID 令牌,请执行以下操作:
下载“发出请求的”应用示例。
按照测试声明应用的更新中的说明,将服务帐号凭据添加到本地环境。
使用标准 Python 3 命令启动 Python 3 示例应用。
从示例应用发送请求并确认操作是否成功。
部署应用
准备好部署应用后,您应该执行以下操作:
如果应用可无错误正常运行,请使用流量拆分功能为更新后的应用缓慢增加流量。请先仔细监控应用是否存在任何问题,若无再将更多流量路由到更新后的应用。
使用其他服务帐号声明身份
当您请求 ID 令牌时,请求默认使用 App Engine 默认服务帐号的身份。在验证令牌时,令牌载荷包含默认服务帐号的电子邮件地址,该地址映射到您的应用的项目 ID。
App Engine 默认服务帐号默认具有较高的权限级别。它可以查看和修改整个 Google Cloud 项目,因此在大多数情况下,如果您的应用需要通过 Cloud 服务进行身份验证,则不适合使用此帐号。
但是,在声明应用身份时,可以安全地使用默认服务帐号,因为您只使用 ID 令牌来验证发送请求的应用的身份。在此过程中,不考虑或不需要已向服务帐号授予的实际权限。
如果您仍希望使用其他服务帐号来处理 ID 令牌请求,请执行以下操作:
将名为
GOOGLE_APPLICATION_CREDENTIALS
的环境变量设置为包含服务帐号凭据的 JSON 文件的路径。请参阅我们提供的建议以了解如何安全存储这些凭据。使用
google.oauth2.id_token.fetch_id_token(request, audience)
检索 ID 令牌。验证此令牌时,令牌载荷将包含新服务帐号的电子邮件地址。