如何使用工作负载身份通过 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?的主要内容,如果未能解决你的问题,请参考以下文章