Google 云(firebase)可调用函数 401:http 调用时出现“未经授权”错误

Geo*_*gii 1 authentication firebase gcloud google-cloud-functions google-iam

我有通过部署的简单测试可调用函数firebase deploy --only functions

这是内容:

export const test = region('europe-west1').https.onCall((data, context) => {
    logger.debug('test call info', data, context);
    return 'hello, world!';
});
Run Code Online (Sandbox Code Playgroud)

我可以通过 HTTP 调用https://europe-west1-{project}.cloudfunctions.net/test并接收来成功调用它{"result": "hello, world!"}

现在想通过 IAM 策略来保护此功能。

  1. 我创建新的服务帐户并加载它的凭据 json。
  2. 我转到控制台并从allUsersCloud Functions Invoker 角色中删除,并使用 Cloud Functions Invoker 角色添加在 #1 中创建的服务帐户。<--- 现在,当我尝试调用我的测试函数时,如预期的那样,我收到 403 Forbidden
  3. 我使用我的 PC 上的服务帐户创建 id-token
const auth = new GoogleAuth({keyFile: './key.json'});
targetAudience = new URL('https://europe-west1-{project}.cloudfunctions.net/test');
const client = await auth.getIdTokenClient(targetAudience as string);
const idToken = await client.idTokenProvider.fetchIdToken(targetAudience as string);
console.log(idToken);
Run Code Online (Sandbox Code Playgroud)
  1. 我验证我的令牌是否正确并通过 为正确的服务帐户颁发https://www.googleapis.com/oauth2/v3/tokeninfo?id_token={{id-token}}
  2. 我用Authorization: Bearer {{id-token}}标头调用我的端点。
  3. 我收到 401 Unauthorized 错误,JSON 告诉我
{
    "error": {
        "message": "Unauthenticated",
        "status": "UNAUTHENTICATED"
    }
}
Run Code Online (Sandbox Code Playgroud)
  1. 我很痛苦,因为在阅读了大部分谷歌云文档后,SO(1,2 )等似乎我做的一切都是正确的,但仍然得到这个错误。

UPD1:向@DazWilkin 提供附加信息

1.

gcloud auth activate-service-account cloud-functions-invoker@{project-id}.iam.gserviceaccount.com --key-file="key.json" 

Activated service account credentials for: [cloud-functions-invoker@{project-id}.iam.gserviceaccount.com]
Run Code Online (Sandbox Code Playgroud)
gcloud projects get-iam-policy {project-id}

...
- members:
  - serviceAccount:cloud-functions-admin@{project-id}.iam.gserviceaccount.com
  - serviceAccount:cloud-functions-invoker@{project-id}.iam.gserviceaccount.com
  role: roles/cloudfunctions.invoker
...
Run Code Online (Sandbox Code Playgroud)
  1. 我复制这个值gcloud auth print-identity-token | clip
  2. 这是我打电话后得到的信息https://www.googleapis.com/oauth2/v3/tokeninfo?id_token={{id-token}}
{
    "aud": "32555940559.apps.googleusercontent.com",
    "azp": "cloud-functions-invoker@{project-id}.iam.gserviceaccount.com",
    "email": "cloud-functions-invoker@{project-id}.iam.gserviceaccount.com",
    "email_verified": "true",
    "exp": "1629157648",
    "iat": "1629154048",
    "iss": "https://accounts.google.com",
    "sub": "114693730231812960252",
    "alg": "RS256",
    "kid": "6ef4bd908591f697a8a9b893b03e6a77eb04e51f",
    "typ": "JWT"
}
Run Code Online (Sandbox Code Playgroud)
  1. 我做了这个卷发(从邮递员那里复制的)。我也尝试过使用命令行进行相同的curl - 得到相同的结果。
curl --location --request POST 'https://europe-west1-{project-id}.cloudfunctions.net/test' \
--header 'Authorization: Bearer 
{token}
' \
--header 'Content-Type: application/json' \
--data-raw '{
    "data": {
        "goodbye": "world:("
    }
}'
Run Code Online (Sandbox Code Playgroud)

UPD2:新输入

仅在可调用函数中才会观察到此行为https.onCall()。如果我使用的https.onRequest()东西工作正常,但我仍然对onCall行为感到困惑,因为我似乎正确地实现了协议(参见我的卷曲)。

Geo*_*gii 8

我的天啊!!!!!

TL;DR:可调用函数仅适用于通过 firebase auth 进行身份验证的最终用户,并且不能与 IAM 令牌一起使用。使用它们的唯一方法是roles/cloudfunctions.invoker分配给allUsers


问题是......我在这里研究可调用函数协议规范: https: //firebase.google.com/docs/functions/callable-reference

它说:

对可调用触发器端点的 HTTP 请求必须是具有以下标头的 POST:

...

  • 可选:授权:持有者
    • 发出请求的登录用户的 Firebase 身份验证用户 ID 令牌。后端自动验证此令牌并使其在处理程序的上下文中可用。如果令牌无效,则请求被拒绝。

我认为规范意味着我们将在这里传递我们的服务帐户id-token,并且我正在尝试这样做(例如使用onRequest函数)。但突然间,token 在那里的解释有所不同。它是通过 firebase 身份验证获得的用户令牌。甚至在文档中还进行了更深入的说明1、2):

警告:Firebase 管理 SDK 中包含的 ID 令牌验证方法旨在验证来自客户端 SDK 的 ID 令牌,而不是您使用管理 SDK 创建的自定义令牌。有关详细信息,请参阅身份验证令牌。

错过这个警告让我损失了三天的痛苦。