如何使用工作负载身份通过 Google Cloud .NET SDK 访问 Google Kubernetes Engine 中的 ESP?

Posted

技术标签:

【中文标题】如何使用工作负载身份通过 Google Cloud .NET SDK 访问 Google Kubernetes Engine 中的 ESP?【英文标题】:How to use Workload identity to access ESP in the Google Kubernetes Engine with the Google Cloud .NET SDK? 【发布时间】:2021-10-07 17:28:54 【问题描述】:

背景

在 Google Kubernetes Engine 上,我们一直在使用 Cloud Endpoints 和可扩展服务代理 (v2) 进行服务到服务身份验证。

服务通过在 HTTP 请求的 Authorization 标头中包含不记名 JWT 令牌来验证自己。

服务的身份已通过 GCP 服务帐户维护,在部署期间,Json 服务帐户密钥被挂载到容器的预定义位置,并且该位置设置为 GOOGLE_APPLICATION_CREDENTIALS env var 的值.

这些服务是用 C# 和 ASP.NET Core 实现的,为了生成实际的 JWT 令牌,我们使用 Google Cloud SDK(https://github.com/googleapis/google-cloud-dotnet 和 https://github.com/googleapis/google-api-dotnet-client),我们在其中调用以下方法:

var credentials = GoogleCredential.GetApplicationDefault();

如果GOOGLE_APPLICATION_CREDENTIALS 正确设置为服务帐户密钥的路径,那么这将返回一个ServiceAccountCredential 对象,我们可以在该对象上调用GetAccessTokenForRequestAsync() 方法,该方法返回实际的JWT 令牌。

var jwtToken = await credentials.GetAccessTokenForRequestAsync("https://other-service.example.com/");
var authHeader = $"Bearer jwtToken";

此过程一直正常运行,没有任何问题。

情况是我们正在从使用手动维护的服务帐户密钥迁移到使用Workload Identity,我无法弄清楚如何正确使用 Google Cloud SDK 来生成必要的 JWT 令牌案例。

问题

当我们在容器中启用 Workload Identity,并且不挂载服务帐户密钥文件,也不设置 GOOGLE_APPLICATION_CREDENTIALS 环境变量时,GoogleCredential.GetApplicationDefault() 调用将返回 ComputeCredential 而不是 ServiceAccountCredential。 如果我们调用 GetAccessTokenForRequestAsync() 方法,它会返回一个不是 JWT 格式的令牌。

我检查了实现,令牌似乎是从元数据服务器检索到的,其中预期的响应格式似乎是标准的 OAuth 2.0 模型(表示为this model class):


  "access_token": "foo",
  "id_token": "bar",
  "token_type": "Bearer",
  ...

GetAccessTokenForRequestAsync() 方法返回access_token 的值。但据我了解,这不是 JWT 令牌,事实上,当我尝试使用它对 ESP 进行身份验证时,它的响应是


 "code": 16,
 "message": "JWT validation failed: Bad JWT format: Invalid JSON in header",
 ..

据我了解,通常id_token 包含 JWT 令牌,它应该可以通过 TokenResponse 对象的IdToken 属性访问,也可以通过 SDK 访问,我尝试像这样访问它:

var jwtToken = ((ComputeCredential)creds.UnderlyingCredential).Token.IdToken;

但这会返回null,因此元数据服务器显然不会在id_token 字段中返回任何内容。

问题

在 GKE 中使用 Workload Identity 时,使用 .NET Google Cloud SDK 获取 JWT 令牌以访问 ESP 的正确方法是什么?

【问题讨论】:

【参考方案1】:

要获取附加服务帐户的 IdToken,您可以使用GoogleCredential.GetApplicationDefault().GetOidcTokenAsync(...)

【讨论】:

感谢@Johannes Passing,这似乎确实有效!我可以再问一个问题吗?以前使用 SA 密钥文件时,JWT 中的 isssub 字段都是 SA 的电子邮件,例如 "iss": "my-service@foo.com", "sub": "my-service@foo.com"。但是对于工作负载标识,iss 始终是https://accounts.google.com。这是意料之中的吗,我们必须调整另一方的 OpenApi 规范以改为接受此颁发者? 抱歉@Johannes Passing,我可以再问一个问题吗? ? 我们是否应该将代码更改为使用GetOidcTokenAsync(),以防ServiceAccountCredential,或者我们仍然应该使用GetAccessTokenForRequestAsync(),而GetOidcTokenAsync()只能与ComputeCredential一起使用? ID 令牌始终使用 https://accounts.google.com 作为 iss 并使用链接到 OIDC metadata 的 JWKS 进行签名。当您authenticate by using a service account key 时,您也在创建一个 JWT,但这不是一个 ID 令牌,而是一个断言(也称为 JWT 持有者),您可以使用它来获取一个 ID 令牌或在。此 JWT 使用 SA 的电子邮件地址作为颁发者,并使用 SA 密钥进行签名。

以上是关于如何使用工作负载身份通过 Google Cloud .NET SDK 访问 Google Kubernetes Engine 中的 ESP?的主要内容,如果未能解决你的问题,请参考以下文章

VMware通过负载平衡器升级支持Google Cloud和Kubernetes

通过 API Key 访问 Google Cloud Function

如何为 Google Cloud Scheduler 设置基本身份验证

Google Cloud Run 最终用户身份验证

如何通过HTTP请求验证Google Cloud Vision

通过代码从 Apache Beam 应用程序向 Google Cloud 进行身份验证