python - 如何使用 API 网关传递给 Cloud Function 的服务帐户的 JWT 在 Cloud Function 中初始化 Google BigQuery 客户端
问题描述
目标:
我已经建立了一个谷歌 API 网关。API 的后端是一个云函数(用 python 编写)。云功能应从 Google BigQuery (BQ) 查询数据。为此,我想创建一个 BQ 客户端 ( google.cloud.bigquery.Client()
)。API 应该由使用不同服务帐户的不同应用程序访问。服务帐户有权访问我项目中的特定数据集。因此,服务帐户/应用程序应该只能查询他们有权查询的数据集。因此,云函数内的 BQ Client 应使用向 API 发送请求的服务帐户进行初始化。
我尝试了什么:
API 使用以下 OpenAPI 定义进行保护,因此需要由服务帐户 SA-EMAIL 签名的 JWT 才能在那里发送请求:
securityDefinitions:
sec-def1:
authorizationUrl: ""
flow: "implicit"
type: "oauth2"
x-google-issuer: "SA-EMAIL"
x-google-jwks_uri: "https://www.googleapis.com/robot/v1/metadata/x509/SA-EMAIL"
x-google-audiences: "SERVICE"
对于使用我的云功能的路径,我使用以下后端配置:
x-google-backend:
address: https://PROJECT-ID.cloudfunctions.net/CLOUD-FUNCTION
path_translation: CONSTANT_ADDRESS
因此,在云功能本身中,我从 API 网关获得了转发的 JWT,X-Forwarded-Authorization
以及已经验证的 base64url 编码的 JWT 有效负载。
我尝试使用 JWT来获取凭据:X-Apigateway-Api-Userinfo
X-Forwarded-Authorization
bearer_token = request.headers.get('X-Forwarded-Authorization')
token = bearer_token.split(" ")[1]
cred = google.auth.credentials.Credentials(token)
起初,这似乎在cred.valid
返回时有效True
,但是当尝试使用google.cloud.bigquery.Client(credentials=cred)
它创建客户端时,会在日志中返回以下错误:
google.auth.exceptions.RefreshError: The credentials do not contain
the necessary fields need to refresh the access token. You must
specify refresh_token, token_uri, client_id, and client_secret.
我对 auth/oauth 没有太多经验,但我认为我没有必要的令牌/属性,错误是说在我的云功能中缺少可用的。另外,我不确定为什么会有RefreshError
,因为我不想刷新令牌(也不要明确地这样做)并且只是再次使用它(可能是不好的做法?)。
问题:
是否有可能以我尝试过的方式或任何其他方式实现我的目标?
解决方案
您的目标是获取调用 API 网关的凭据,并在您的 Cloud Functions 中重用它来调用 BigQuery。
可悲的是,你不能。为什么?因为 API Gateway 会阻止您实现这一目标(出于安全原因,这是一个好消息)。JWT 令牌已正确转发到您的 Cloud Functions,但签名部分已被删除(您只收到 JWT 令牌的标头和正文)。
API Gateway 已完成安全验证,您必须依赖该身份验证。
解决方案是什么?
我的解决方案如下:在您收到的截断 JWT 中,您可以获取正文并获取服务帐户电子邮件。从那里,您可以使用 Cloud Functions 服务帐户来模拟您收到的服务帐户电子邮件。
像这样,Cloud Functions 服务帐户只需要模拟这些服务帐户的权限,而您保留在原始服务帐户上提供的权限。
我没有看到其他解决方案来解决您的问题。
推荐阅读
- python - 如果列表中存在值,则将它们放在 Python 中列表的末尾
- python - 如何在网络摄像头视频流上显示变量值?(蟒蛇OpenCV)
- java - 我们如何导入非公开类?
- angular - 如何在 Angular Jasmine Spec 中测试主题和可观察的返回值?
- angular - 数据路径“”不应该有额外的属性(stylePreprocessorOptions)
- php - session->getFlashData 在视图中显示不止一次
- r - 如何创建一个新列,其中每一行都是来自另一列 (BE) 的值,以具有列名称 (BE) 的另一列为条件?
- go - 用新的 caseClause 重写 AST switch stmt
- mongodb - mongodb连接不上27018端口
- angular - 在Angular 9中使用Angular Material Dialog发送数据,而不关闭它