【发布时间】:2020-07-22 08:13:41
【问题描述】:
我正在尝试使用 Cloud Tasks 调用 Cloud Run 服务,如文档 here 中所述。
我有一个正在运行的 Cloud Run 服务。如果我将服务设为可公开访问,它会按预期运行。
我创建了一个云队列,并使用本地脚本安排了云任务。这个是用我自己的账号。脚本是这样的
from google.cloud import tasks_v2
client = tasks_v2.CloudTasksClient()
project = 'my-project'
queue = 'my-queue'
location = 'europe-west1'
url = 'https://url_to_my_service'
parent = client.queue_path(project, location, queue)
task = {
'http_request': {
'http_method': 'GET',
'url': url,
'oidc_token': {
'service_account_email': 'my-service-account@my-project.iam.gserviceaccount.com'
}
}
}
response = client.create_task(parent, task)
print('Created task {}'.format(response.name))
我看到任务出现在队列中,但它失败并立即重试。原因(通过检查日志)是 Cloud Run 服务返回 401 响应。
我自己的用户具有“服务帐户令牌创建者”和“服务帐户用户”的角色。它没有明确的“Cloud Tasks Enqueuer”,但由于我能够在队列中创建任务,我想我已经继承了所需的权限。 服务帐户“my-service-account@my-project.iam.gserviceaccount.com”(我在任务中使用它来获取 OIDC 令牌)具有以下角色:
- Cloud Tasks Enqueuer(虽然我认为它不需要这个,因为我正在使用自己的帐户创建任务)
- 云任务任务运行器
- 云任务查看器
- 服务帐户令牌创建者(我不确定是否应该将其添加到我自己的帐户 - 安排任务的帐户 - 还是应该执行调用 Cloud Run 的服务帐户)
- 服务帐户用户(此处相同)
- Cloud Run 调用者
所以我做了一个肮脏的把戏:我为服务帐户创建了一个密钥文件,将其下载到本地,然后通过将一个帐户添加到我的 gcloud 配置中来在本地模拟该密钥文件。接下来,我运行
curl -H "Authorization: Bearer $(gcloud auth print-identity-token)" https://url_to_my_service
这行得通! (顺便说一句,我切换回自己的帐户时也可以使用)
最终测试:如果我在创建任务时从任务中删除了oidc_token,我会收到来自 Cloud Run 的 403 响应!不是401...
如果我从服务帐户中删除“Cloud Run Invoker”角色并使用 curl 在本地重试,我也会得到 403 而不是 401。
如果我最终让 Cloud Run 服务可公开访问,那么一切正常。
因此,Cloud Task 似乎无法为服务帐户生成令牌以在 Cloud Run 服务上正确进行身份验证。
我错过了什么?
【问题讨论】:
-
我也是.. 遵循了文档:cloud.google.com/tasks/docs/creating-http-target-tasks,但我收到了来自目标服务的 401 响应。将任务加入队列的服务帐户应该只需要权限 1.
Cloud Tasks Enqueuer2.Service Account User3.Cloud Run Invoker(或您所针对的任何谷歌服务的调用者)。入队服务帐户电子邮件在入队之前被添加到任务中,以便 Cloud Tasks Queue 可以使用它来生成令牌......我将看看这个问题是否像你的那样在 24 小时内解决。这太令人沮丧了 -
也许还值得注意:我最近在尝试从 Cloud Scheduler 触发 Cloud Run 时也收到了 401 响应。我也在使用 OIDC 令牌,结果发现我在观众中设置了错误的 URL。对于 Cloud Tasks,获取 OIDC 令牌似乎是在幕后进行的,但我现在感觉那里出了点问题。
-
我想通了。对我来说令人沮丧的是我之前必须解决这个问题......如果您没有为
oidc_token明确填充audience字段,则使用任务中的目标url,在上面的示例中:https://url_to_my_service。这里的问题是,如果您将 Cloud Run 与自定义域(而不是云运行生成的域)一起使用,那么您将收到错误消息,因为 OIDCaudience不支持自定义域。我的解决方法是使用 Cloud Run 生成的 URL 显式填充受众,然后它就起作用了。
标签: service-accounts google-cloud-run google-cloud-tasks