【问题标题】:Get ServiceAccountCredentials from ComputeEngineCredentials to do user impersonation从 ComputeEngineCredentials 获取 ServiceAccountCredentials 以进行用户模拟
【发布时间】: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 的工作原理了。我认为本地发生的事情是这样的:

  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正在使用的凭据已经是我要为其获取密钥的同一服务帐户的凭据。

【问题讨论】:

  • 如果 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


【解决方案1】:

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

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

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

【讨论】:

    【解决方案2】:

    您需要将 Cloud Run 服务告知run as your service account

    gcloud run deploy --image IMAGE_URL --service-account SERVICE_ACCOUNT
    

    【讨论】:

    • 我已经这样做了,但它不起作用。我可能会错过什么?
    • 确保您不要在云端运行时设置 GOOGLE_APPLICATION_CREDENTIALS
    • 我没有,虽然我正在设置另一个环境变量,但我不希望这会发生冲突。
    • 您遇到错误了吗?是什么让您认为凭证没有被使用?
    • 经过几个小时的调试,我已经更新了问题,我原来的问题是在错误的轨道上。
    猜你喜欢
    • 2019-03-06
    • 1970-01-01
    • 2011-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-28
    • 1970-01-01
    • 2013-04-19
    相关资源
    最近更新 更多