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