【问题标题】:Receiving 401 when accessing authenticated Google Cloud Function访问经过身份验证的 Google Cloud Function 时收到 401
【发布时间】:2021-06-17 20:19:32
【问题描述】:

我正在尝试从另一个云函数调用经过身份验证的基于 HTTP 的云函数。为简洁起见,我们分别称它们为 CF1 和 CF2;因此我希望从 CF1 调用 CF2。

按照 Google 文档中给出的示例:Authenticating for Invocation,我为 CF2 创建了一个新服务帐户,然后使用 roles/cloudfunctions.admin 将其附加到 CF1。我下载了一个用于本地测试的服务密钥 Functions Framework,将其设置为应用程序默认凭据(ADC);因此我本地机器上的 CF2 连接到 GCP 上的 CF1,通过 ADC 验证为 CF2 的服务帐户。

我已经成功在 Cloud Functions 上部署了 CF1,并且正在测试我本地机器上的 CF2 是否可以访问 CF1,这时我惊讶地收到了 HTTP 401。

作为参考,这里是有问题的代码,它与谷歌文档提供的示例几乎相同:

        String serviceUrl = "<cf1-url>";
        GoogleCredentials credentials = GoogleCredentials.getApplicationDefault();

        if (!(credentials instanceof IdTokenProvider)) {
            throw new IllegalArgumentException("Credentials are not an instance of IdTokenProvider.");
        }

        IdTokenCredentials tokenCredential =
                IdTokenCredentials.newBuilder()
                        .setIdTokenProvider((IdTokenProvider) credentials)
                        .setTargetAudience(serviceUrl)
                        .build();

        GenericUrl genericUrl = new GenericUrl(serviceUrl);
        HttpCredentialsAdapter adapter = new HttpCredentialsAdapter(tokenCredential);
        HttpTransport transport = new NetHttpTransport();
        com.google.api.client.http.HttpRequest request = transport.createRequestFactory(adapter).buildGetRequest(genericUrl);
        com.google.api.client.http.HttpResponse response = request.execute();

我试过参考:

但我无法从这些问题中找到解决问题的方法。

进一步测试显示,通过客户端 SDK 生成的身份令牌: tokenCredential.getIdToken().getTokenValue() 与 GCloud CLI 命令 gcloud auth print-identity-token 不同。我可以使用 GCloud CLI 生成的身份令牌直接调用 CF1(例如通过 Postman/cURL 并作为 CF2 的服务帐户进行身份验证),但不能使用客户端 SDK 打印的身份令牌。这是一个惊喜,因为我使用 CF 2 的服务帐户密钥作为 ADC,并通过gcloud auth activate-service-account 授权它访问 gcloud。

在我看来,服务账户和云功能的权限没有问题,因为我可以直接调用CF1;因此,这似乎是代码的问题。但是,我无法确定 401 错误的原因。

【问题讨论】:

  • 您是否检查了您的 java 应用程序生成的身份令牌的主体?你确定这个身份是经过授权的吗?
  • 嗨@guillaumeblaquiere,对不起,我对OAuth不太熟悉。如果委托人指的是凭据的“受众”字段,那么我已将其设置为 CF1 的 URL。如果委托人指的是身份令牌的用户,那么我查看了通过其电子邮件字段接收并验证的 JWT,该令牌是为 CF 2 的服务帐户颁发的,该帐户是 CF1 上的云功能管理员.而且由于我可以通过 gcloud CLI 将 CF1 作为 CF2 的服务帐户调用,所以在我看来,到目前为止权限和身份没有问题。
  • GCloud 和 ADC(应用程序默认凭据)不一样。您可以使用 gcloud(gcloud auth login 用于 gcloud CLI 命令(如 gcloud auth print-identity-token)和gcloud auth application-default login 用于使用 Google Cloud 客户端库的应用程序和代码 -> 您的案例)有 2 个不同的。这就是为什么,你的java代码生成的令牌的电子邮件很重要,你需要确保这个电子邮件被授权调用目标函数。
  • 嗨@guillaumeblaquiere,感谢您的回复。我确定电子邮件被授权访问该功能的原因是因为我通过gcloud auth activate-service-account 在gcloud 上进行了身份验证,如果我从gcloud auth activate-service-account 正确理解,它执行与gcloud auth login 相同的功能,除了我正在使用服务帐户凭据而不是用户帐户凭据。
  • 为了确认,我使用gcloud config list并验证account字段中使用的帐户是CF 2的服务帐户。因此,据我了解使用@987654337打印的身份令牌@ 确实是 CF 2 的服务帐户的身份令牌。这个服务帐号也被设置为ADC,并且从Google APIs收到的JWT的client_email字段也被验证为CF2的服务帐号。

标签: java google-cloud-platform google-cloud-functions


【解决方案1】:

目标受众,您的serviceURL,必须是原始 url,这是由 Cloud Functions 服务提供的。

如果您添加参数(查询或路径),它将不起作用。

【讨论】:

    猜你喜欢
    • 2015-12-07
    • 1970-01-01
    • 1970-01-01
    • 2019-01-29
    • 2016-01-15
    • 1970-01-01
    • 2020-10-31
    • 1970-01-01
    • 2020-08-25
    相关资源
    最近更新 更多