1

我正在部署一个 Java API,它通过 Domain-widge 委派进行用户模拟以访问用户的日历。为此,我创建了一个服务帐户,完成了委派并为其授予了正确的权限和对用户日历的访问权限。

在本地开发时,我一直在使用 JSON 格式的服务帐户的下载密钥,并使用 GOOGLE_APPLICATION_CREDENTIALS 环境变量指向它。在我的代码中,我使用 Java 客户端库创建这样的凭据:

@Bean
@Qualifier("userCredentials")
public GoogleCredentials impersonateCalendarOwner() throws IOException {
    final List<String> scopes = Collections.singletonList(CalendarScopes.CALENDAR);

    return  ((ServiceAccountCredentials) GoogleCredentials.getApplicationDefault())
            .toBuilder()
            .setServiceAccountUser(GOOGLE_CALENDARS_OWNER)
            .build()
            .createScoped(scopes);
}

这在本地运行良好,但在 Cloud Run 中运行时,我得到:

nested exception is java.lang.ClassCastException: 
class com.google.auth.oauth2.ComputeEngineCredentials cannot be cast to 
class com.google.auth.oauth2.ServiceAccountCredentials

经过数小时的调试,我想我终于明白了它是如何getApplicationDefault工作的。我认为本地发生的事情是这样的:

  1. getApplicationDefault 首先查看环境变量 GOOGLE_APPLICATION_CREDENTIALS,因为它已设置,所以它从该文件中读取凭据
  2. 因为该文件是服务帐户密钥文件,所以它会创建一个 ServiceAccountCredentials 实例,因此“强制转换”成功。

在 Cloud Run 中,它会这样发生:

  1. getApplicationDefault 首先查看环境变量 GOOGLE_APPLICATION_CREDENTIALS,但在 Cloud Run 上未设置
  2. 因此,它通过从元数据服务器获取凭据并将它们作为 ComputeEngineCredentials 的实例返回(因为元数据服务器不分发服务帐户的密钥),从而回退到服务帐户身份。
  3. 然后它尝试将 ComputeEngineCredentials 转换为 ServiceAccountCredentials,这显然不起作用。

所以现在我的问题仍然存在:

  1. 如何将一些 ComputeEngineCredentials 转换为 ServiceAccountCredentials?
  2. 是否有其他方法可以将凭据作为 ServiceAccountCredentials 的实例来获取?
  3. 是否有其他不需要 ServiceAccountCredentials 实例的用户模拟方法?

我目前的想法是使用我得到的 ComputeEngineCredentials,在服务启动时从 Secret Manager 获取服务帐户 JSON 密钥文件,然后将该文件传递给 ServiceAccountCredentials.fromStream 但这感觉像是一个额外的步骤,因为我将使用的 ComputeEngineCredentials 是已经是我要为其获取密钥的同一服务帐户的凭据。

4

2 回答 2

2

实例元数据(元数据服务器)提供的凭据不包括签署请求所需的服务帐户私钥。

因此,您尝试使用的服务帐户模拟代码将不起作用。您将需要使用包含私钥的实际服务帐户 JSON。

我的建议是设置具有访问 Secret Manager 的角色的默认服务帐户。将服务帐户 JSON 密钥文件作为数据存储在 Secret Manager 中。在您的程序启动时获取服务帐户 JSON 内容并继续使用您的模拟代码。

于 2021-01-16T19:02:29.577 回答
1

您需要告诉 Cloud Run 服务作为您的服务帐号运行

gcloud run deploy --image IMAGE_URL --service-account SERVICE_ACCOUNT
于 2021-01-15T20:32:40.807 回答