【发布时间】:2021-01-15 20:18:19
【问题描述】:
我正在部署一个 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 的工作原理了。我认为本地发生的事情是这样的:
- getApplicationDefault 首先查看环境变量 GOOGLE_APPLICATION_CREDENTIALS,因为它已设置,它会从该文件中读取凭据
- 由于该文件是服务帐户密钥文件,因此它会创建一个 ServiceAccountCredentials 实例,因此“强制转换”成功。
在 Cloud Run 中,情况如下:
- getApplicationDefault 首先查看环境变量 GOOGLE_APPLICATION_CREDENTIALS,但在 Cloud Run 上未设置
- 因此,它通过从元数据服务器获取凭据并将其作为 ComputeEngineCredentials 实例返回到运行修订的服务帐户身份(因为元数据服务器不分发服务帐户的密钥) .
- 然后它尝试将 ComputeEngineCredentials 强制转换为 ServiceAccountCredentials,这显然不起作用。
所以现在我的问题仍然存在:
- 如何将一些 ComputeEngineCredentials 转换为 ServiceAccountCredentials?
- 是否有其他方法可以将凭据作为 ServiceAccountCredentials 的实例来获取?
- 是否有其他不需要 ServiceAccountCredentials 实例的用户模拟方法?
我目前的想法是使用我得到的 ComputeEngineCredentials,在服务启动时从 Secret Manager 获取服务帐户 JSON 密钥文件,然后将该文件传递给 ServiceAccountCredentials.fromStream 但感觉像是一个额外的步骤,因为我会使用 ComputeEngineCredentials正在使用的凭据已经是我要为其获取密钥的同一服务帐户的凭据。
【问题讨论】:
-
如果 Seth Vargo 的回答不能解决您的问题,那么您可能错误地使用了
GoogleCredentials。显示需要凭据的代码。大多数 Google Cloud Service 客户端 (SDK) 会自动从元数据服务器获取凭据,而不需要您在问题中使用的代码。 -
@JohnHanley 经过数小时的调试,我已经更新了这个问题,我原来的问题是在错误的轨道上。
-
在 Cloud Run、Cloud Functions、Compute Engine 等服务下运行时从元数据服务器获取凭据,只有 Access Token 可用。签名所需的私钥不可用。因此,您尝试使用的代码将不起作用。我的建议是设置具有访问 Secret Manager 的角色的默认服务帐户。将服务帐户 JSON 密钥文件作为数据存储在 Secret Manager 中。在您的程序启动时获取服务帐户 JSON 内容并继续使用您的模拟代码。
-
这是我想追的曲目,谢谢确认!
标签: java google-cloud-run google-secret-manager