从Cloud Run调用Cloud Function遇403错误,Terraform配置IAM仍失败
Cloud Run调用Cloud Function出现403错误的排查与解决
从Cloud Run调用Cloud Function是完全支持的,你遇到的403错误通常是权限配置遗漏或调用时未正确携带身份凭证导致的,以下是具体排查方向和解决方法:
排查方向1:Cloud Run的服务账号未被授予Cloud Function调用权限
你的Terraform配置中,GCF的roles/cloudfunctions.invoker角色绑定了var.service_accounts,但需要确认Cloud Run服务实际使用的服务账号是否包含在这个变量里:
- Cloud Run默认使用
PROJECT_ID-compute@developer.gserviceaccount.com(Compute Engine默认服务账号),如果你的var.service_accounts没有包含这个账号,GCF会拒绝Cloud Run的请求。 - 也可以在Cloud Run控制台的「服务详情→修订版本」中查看当前使用的服务账号,确认该账号是否在GCF的IAM成员列表中。
- 另外,你使用的
google_cloudfunctions_function_iam_policy会替换GCF的整个IAM策略,如果之前有其他必要的绑定(比如自己的测试账号),会被覆盖,但核心问题还是Cloud Run的服务账号是否在invoker角色中。
排查方向2:调用Cloud Function时未携带身份认证令牌
GCF默认不允许未认证调用(除非你手动开启),直接用axios调用URL会因为缺少凭证被拒绝。Cloud Run的服务账号需要生成ID令牌,通过Authorization头传递给GCF:
- 你当前的代码
axios.post(this._cloudFunctionUrl as string)没有添加任何认证头,这是导致403的常见原因。
解决方法
1. 确保Cloud Run服务账号拥有GCF调用权限
修改Terraform配置,直接将Cloud Run的服务账号添加到GCF的invoker角色中,避免依赖变量可能的遗漏:
data "google_iam_policy" "invoker" { binding { role = "roles/cloudfunctions.invoker" members = [ # 直接引用Cloud Run的服务账号 "serviceAccount:${google_cloud_run_service.crun.service_account}" ] } } resource "google_cloudfunctions_function_iam_policy" "policy" { project = google_cloudfunctions_function.func.project region = google_cloudfunctions_function.func.region cloud_function = google_cloudfunctions_function.func.name policy_data = data.google_iam_policy.invoker.policy_data }
如果不想替换整个GCF的IAM策略,改用google_cloudfunctions_function_iam_binding追加绑定(更安全,不会覆盖原有配置):
resource "google_cloudfunctions_function_iam_binding" "invoker" { project = google_cloudfunctions_function.func.project region = google_cloudfunctions_function.func.region cloud_function = google_cloudfunctions_function.func.name role = "roles/cloudfunctions.invoker" members = [ "serviceAccount:${google_cloud_run_service.crun.service_account}" ] }
2. 修改Cloud Run代码,添加身份认证逻辑
使用Google官方的google-auth-library获取ID令牌,并在axios请求中携带:
const { GoogleAuth } = require('google-auth-library'); const axios = require('axios'); async function callCloudFunction() { const gcfUrl = process.env.CLOUD_FUNCTION_URL; const auth = new GoogleAuth(); // 获取目标GCF的ID令牌 const idToken = await auth.getIdToken(gcfUrl); try { const response = await axios.post(gcfUrl, {}, { headers: { 'Authorization': `Bearer ${idToken}` } }); return response.data; } catch (error) { console.error('调用GCF失败:', error); throw error; } }
3. (可选)临时开启GCF的未认证调用(不推荐生产环境)
如果只是测试,可以在GCF控制台开启「允许未认证调用」,但生产环境必须关闭,避免安全风险。
内容的提问来源于stack exchange,提问作者jereczq22
相关产品推荐
相关产品推荐

