【发布时间】: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();
我试过参考:
- Google Cloud Platform - cloud functions API - 401 Unauthorized
- Cloud Function Permissions (403 when invoking from another cloud function)
- Google Cloud Function Authorization Failing
但我无法从这些问题中找到解决问题的方法。
进一步测试显示,通过客户端 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