14

我到处看了看,似乎人们要么使用 pubsub、应用程序引擎 http 或没有身份验证的 http。没有太多人展示他们通过带有 oidc 令牌的身份验证访问功能以访问谷歌功能的工作。

我检查了:无法从 GCP 调度程序调用 Google Cloud Function,但似乎没有任何效果。

我遵循的文档: https ://cloud.google.com/scheduler/docs/http-target-auth#using-gcloud_1

  1. 创建了一个新的服务帐户
  2. 设置角色(云调度服务代理/云功能服务代理/云调度管理员/云功能调用者......甚至尝试过所有者!)
  3. 部署了不允许公共(未经身份验证)访问的谷歌函数(一个简单的 helloworld 函数)
  4. 在云调度程序上设置 cron 作业,以使用此配置针对新部署的功能每分钟运行一次:
    • url = helloworld 函数
    • oidc 令牌
    • 新创建的服务帐户
    • 观众设置为 hello world 功能 url

云调度程序日志的结果:

Expand all | Collapse all{
 httpRequest: {
 }
 insertId: "ibboa4fg7l1s9"  
 jsonPayload: {
  @type: "type.googleapis.com/google.cloud.scheduler.logging.AttemptFinished"   
  jobName: "projects/project/locations/region/jobs/tester"   
  status: "PERMISSION_DENIED"   
  targetType: "HTTP"   
  url: "https://region-project.cloudfunctions.net/tester"   
 }
 logName: "projects/project/logs/cloudscheduler.googleapis.com%2Fexecutions"  
 receiveTimestamp: "2020-04-15T17:50:14.287689800Z"  
 resource: {…}  
 severity: "ERROR"  
 timestamp: "2020-04-15T17:50:14.287689800Z" 

我看到一个解决方案显示有人创建了一个新项目来实现它,还有其他的吗?

感谢提供的任何帮助。

更新

新的 Google 功能 - 在中央运行(与我的应用引擎应用相同)

新服务帐户 - 具有所有者角色

新计划任务 - 信息

新计划任务 - 状态

新计划任务 - 日志

实际修复

如果您缺少 cloudscheduler 服务帐户(例如:service-1231231231412@gcp-sa-cloudscheduler.iam.gserviceaccount.com),Http 身份验证任务将无法工作。为了解决这个问题,我必须禁用 api 并重新启用它,它给了我服务帐户,我没有使用这个服务帐户,但是,这是我这样做后唯一改变的因素。

4

4 回答 4

8

这些是您必须采取的确切步骤。确保不要跳过第二步,它会设置服务帐户的调用者权限,以便调度程序能够使用该服务帐户的 OIDC 信息调用 HTTP 云函数。注意:为简单起见,我在这里选择默认服务帐户,但是,为此目的创建一个具有较少权限的单独服务帐户是明智的。

# Create cloud function
gcloud functions deploy my_function \
  --entry-point=my_entrypoint \
  --runtime=python37 \
  --trigger-http \
  --region=europe-west1 \
  --project=${PROJECT_ID}

# Set invoke permissions
gcloud functions add-iam-policy-binding my_function \
  --region=europe-west1 \
  --member=serviceAccount:${PROJECT_ID}@appspot.gserviceaccount.com \
  --role="roles/cloudfunctions.invoker" \
  --project=${PROJECT_ID}

# Deploy scheduler
gcloud scheduler jobs create http my_job \
  --schedule="every 60 minutes" \
  --uri="https://europe-west1-${PROJECT_ID}.cloudfunctions.net/my_function/" \
  --http-method=POST \
  --oidc-service-account-email="${PROJECT_ID}@appspot.gserviceaccount.com" \
  --oidc-token-audience="https://europe-west1-${PROJECT_ID}.cloudfunctions.net/my_function" \
  --project=${PROJECT_ID}
于 2020-10-27T15:53:35.690 回答
5

我想我会扩展 Nebulastic 的答案,因为我刚刚发现有一些边缘情况,他们的答案并不完整。

创建云函数

# Create cloud function
gcloud functions deploy my_function \
  --entry-point=my_entrypoint \
  --runtime=python37 \
  --trigger-http \
  --region=europe-west1 \
  --project=${PROJECT_ID}

您可能想要更改entry-pointruntime或等字段trigger。在Cloud Functions 部署文档中阅读更多内容。

创建 Cloud Scheduler 作业:

# Deploy scheduler
gcloud scheduler jobs create http my_job \
  --schedule="every 60 minutes" \
  --uri="https://europe-west1-${PROJECT_ID}.cloudfunctions.net/my_function/" \
  --http-method=POST \
  --oidc-service-account-email="${SERVICE_ACCOUNT_EMAIL}" \
  --oidc-token-audience="https://europe-west1-${PROJECT_ID}.cloudfunctions.net/my_function" \
  --project=${PROJECT_ID}

有关更多信息,请参阅Cloud Schedule 文档

请注意,任何服务帐户都可用于 OIDC 身份验证,而不仅仅是为项目创建的默认帐户。

此外,您不需要gcloud functions add-iam-policy-binding像 Nebulastic 的回答中建议的那样调用,而是可以将Cloud Functions Invoker角色设置为传递给的服务帐户--oidc-service-account-email(请参阅添加角色的文档)。这样,此类服务帐户将有权调用任何云功能,而无需在每个部署上授予此类权限。这并不是说 Nebulastic 建议的方法不正确,您也可以这样做。

您可以通过在 Cloud Functions 列表 -> Permissions 选项卡 -> Roles 子选项卡 -> 打开 Cloud Functions Invoker 行中单击其名称来验证哪些服务帐户有权调用该函数。

功能权限


现在对于边缘情况:

入口 - 仅允许内部流量

尽管文档有建议,但将函数的入口设置设置为“仅允许内部流量”并不包含 Cloud Scheduler 的流量,并且会导致 PERMISSION_DENIED 错误。这是 GCP 开发人员所知道的,将来可能会修复。现在,使用“允许所有流量”(或者--ingress-settings=all如果使用 gcloud 部署)。

入口设置

URL参数和OIDC认证

如果您的 Cloud Schedule 作业使用 OIDC 身份验证,并且您的函数需要URL 参数形式的参数- 例如。...my_function?key=value- 那么您必须确保 OIDC 受众包含 URL 参数。仅在 URL 字段中指定 URL 参数,但如果它们出现在 Audience 字段中,请求将返回 403 UNAUTHENTICATED。请注意,如果您未手动指定 OIDC 受众,则会使用 URL 的副本自动填充 OIDC 受众。这是 GCP 开发人员知道的另一个问题,并且可能正在修复或更新文档。

tldr:不要将 URL 参数放在 OIDC 受众 URL 中 - 仅在 URL 字段中:

  --uri="https://europe-west1-${PROJECT_ID}.cloudfunctions.net/my_function?key=value" \
  --oidc-token-audience="https://europe-west1-${PROJECT_ID}.cloudfunctions.net/my_function" \

JSON 参数和 Content-Type

如果您选择使用 Cloud Scheduler 作业调用带有 JSON 参数的函数 - 例如。{"key": "value"}正文字段中 - 那么您将需要:

  • 在函数中手动解析 JSON - 例如Flask 的 get_json将不起作用,除非您使用force=True.

  • gcloud scheduler jobs create使用而不是从控制台创建函数,并确保通过添加以下标志指定 Content-Type 标头:--headers Content-Type=application/json

Cloud Scheduler API 在 2019 年 3 月 19 日之前启用

授予此角色的 Cloud Scheduler 服务帐户会在您启用 Cloud Scheduler API 时自动设置,除非您在 2019 年 3 月 19 日之前启用它,在这种情况下,您必须手动添加角色。

这似乎是作者问题中列出的问题背后的原因。有关更多信息,请参阅文档。这导致问题的原因如下:

Cloud Scheduler 本身必须具有自己的服务帐户,该服务帐户已授予 Cloud Scheduler 服务代理角色。这样它就可以代表您的客户服务帐户生成标头令牌以向您的目标进行身份验证。


消息来源:刚刚花了一周时间与他们的一名支持代理一起解决所有这些问题——向帮助发现所有这些怪癖的杰森大喊大叫。他们正在解决这些问题,但我想我会把这些信息留在这里,直到(如果有的话)这些事情得到解决。

于 2020-12-17T07:04:51.250 回答
3

对于在 2019 年 3 月 19 日之后激活 api 的用户来说,这是一个令人沮丧的错误。

对于 2019 年 3 月 19 日之前的用户,谷歌已注意到以下修复;

此过程允许您在不禁用和重新启用 API 的情况下解决问题。

谷歌有一个解决这个问题的文件并指出

“仅当您在 2019 年 3 月 19 日之前启用 Cloud Scheduler API 时才需要这样做。”

https://cloud.google.com/scheduler/docs/http-target-auth#add

使用控制台:

使用控制台

使用 gcloud

查找您的项目编号:

gcloud projects describe [project-id] --format='table(projectNumber)'
Replacing [project-id] with your project ID.

抄下号码。

使用您复制的项目编号为 Cloud Scheduler 服务帐户授予 Cloud Scheduler 服务代理角色:

gcloud projects add-iam-policy-binding [project-id] --member serviceAccount:service-[project-number]@gcp-sa-cloudscheduler.iam.gserviceaccount.com --role roles/cloudscheduler.serviceAgent

将 [project-id] 替换为您的项目 ID,将 [project-number] 替换为上面的项目编号。

上述评论的注意事项:禁用和重新启用 API 也可以解决问题(因为它会自动执行此过程),但对于不想破坏其当前任务的任何人来说,它都是破坏性的。

于 2021-03-19T14:05:08.413 回答
-1

1.我创建了一个 clod 函数(与我的 App Engine 应用程序在同一区域),它不允许公共访问

2.我创建了一个具有所有者角色的服务帐户

3.我创建了云调度器作业:

url = https://europe-west2-my-project.cloudfunctions.net/my-function

oidc 令牌

新创建的服务帐户

观众 = https://europe-west2-my-project.cloudfunctions.net/my-function

在此处输入图像描述

一切都按预期工作。请仔细检查您的设置,因为它应该可以工作。

于 2020-04-15T20:41:48.710 回答