【问题标题】:Google cloud (firebase) callable function 401: "unauthorized" error when called by http谷歌云(firebase)可调用函数401:http调用时出现“未经授权”错误
【发布时间】:2021-08-16 09:59:00
【问题描述】:

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

这里是内容:

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

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

现在想通过 IAM 策略保护这个函数。

  1. 我创建新的服务帐户并加载它的凭据 json。
  2. 我转到控制台并从 allUsers 中删除 Cloud Functions Invoker 角色,并添加在 #1 中创建的具有 Cloud Functions Invoker 角色的服务帐户。
  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);
  1. 我验证我的令牌是正确的,并通过https://www.googleapis.com/oauth2/v3/tokeninfo?id_token={{id-token}} 为正确的服务帐户颁发。
  2. 我用Authorization: Bearer {{id-token}} 标头调用我的端点。
  3. 我收到 401 未经授权的错误,JSON 告诉我
{
    "error": {
        "message": "Unauthenticated",
        "status": "UNAUTHENTICATED"
    }
}
  1. 我很痛苦,因为在阅读了大部分谷歌云文档、SO(12)等之后,我似乎做的一切都是正确的,但仍然出现此错误。

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]
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
...
  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"
}
  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:("
    }
}'

UPD2:新输入

这种行为仅在 callable 函数https.onCall() 中观察到。如果我使用https.onRequest() 一切正常,但我仍然对onCall 的行为感到困惑,因为我似乎正确地实现了protocol(参见我的curl)。

【问题讨论】:

  • 看来 (!?) 正确。您可以在gcloud auth activate-service-account@](cloud.google.com/sdk/gcloud/reference/auth/…) 之后使用gcloud 到 [gcloud auth print-identity-token](cloud.google.com/sdk/gcloud/reference/auth/print-identity-token)。这将消除您的客户端生成的身份令牌是否不正确。尽管您使用端点进行的检查确实提供了一种很好的检查方式。
  • 您无需删除现有账户,只需将新创建的账户添加到 IAM 调用者角色即可
  • 可能包含(编辑)gcloud projects get-iam-policy 的结果,以便项目确认调用程序绑定。
  • IAM 政策看起来不错!
  • 如果您只是使用{token} 代替您问题中的值,那么我不明白为什么它不起作用!

标签: firebase authentication google-cloud-functions gcloud google-iam


【解决方案1】:

天哪!!!!!!

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


问题是...我在这里查看 callable 函数协议规范:https://firebase.google.com/docs/functions/callable-reference

上面写着:

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

...

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

我在想规范意味着我们将在这里传递我们的服务帐户 id-token,我正在尝试这样做(例如使用onRequest 函数)。但是突然之间,token 在那里的解释不同。它是通过 firebase auth 获得的用户令牌。它甚至在文档中更深一层(12):

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

错过这个警告让我痛苦了 3 天。

【讨论】:

    猜你喜欢
    • 2022-01-18
    • 1970-01-01
    • 2012-02-22
    • 1970-01-01
    • 2020-11-15
    • 2012-06-29
    • 1970-01-01
    • 1970-01-01
    • 2014-06-24
    相关资源
    最近更新 更多