使用 Workload Identity 从 GKE 向 Google Cloud Firestore 进行身份验证

Jam*_*ams 7 node.js kubernetes google-kubernetes-engine google-iam google-cloud-firestore

我正在尝试编写一个简单的后端来访问我的 Google Cloud Firestore,它位于 Google Kubernetes Engine 中。在我的本地,我使用以下代码对 Firestore 进行身份验证,如 Google 文档中所述。

if (process.env.NODE_ENV !== 'production') {
  const result = require('dotenv').config()
  //Additional error handling here
}
Run Code Online (Sandbox Code Playgroud)

这会提取 GOOGLE_APPLICATION_CREDENTIALS 环境变量,并使用我google-application-credentals.json通过创建具有该角色的服务帐户时获得的my 来填充它"Cloud Datastore User"

所以,在本地,我的代码运行良好。我可以到达我的 Firestore 并执行我需要执行的所有操作。然而,一旦我部署到GKE,问题就出现了。

我按照此Google 文档为我的集群设置了工作负载身份,我创建了一个部署,并通过运行以下命令验证所有 Pod 是否都使用正确的 IAM 服务帐户:

kubectl exec -it POD_NAME -c CONTAINER_NAME -n NAMESPACE sh
> gcloud auth list
Run Code Online (Sandbox Code Playgroud)

我从文档中得到的印象是,只要上述内容成立,我的服务就会处理身份验证。我真的不确定为什么,但我的 Firestore() 实例的行为就好像它没有访问 Firestore 所需的凭据。

如果有帮助的话,下面是我的实例声明和实现:

kubectl exec -it POD_NAME -c CONTAINER_NAME -n NAMESPACE sh
> gcloud auth list
Run Code Online (Sandbox Code Playgroud)

更新:

在绝望中,我决定拆除所有东西并重建它。一步一步地跟踪所有内容后,我似乎遇到了错误,或者(更有可能)我第一次做了一些轻微的错误。我现在可以连接到我的后端服务。但是,我现在遇到了不同的错误。发送任何请求后(我使用的是 GraphQL,但本质上它是任何 REST 调用),我会返回 404。

检查日志会产生以下结果:

'Getting metadata from plugin failed with error: Could not refresh access token: A Not Found error was returned while attempting to retrieve an accesstoken for the Compute Engine built-in service account. This may be because the Compute Engine instance does not have any permission scopes specified: Could not refresh access token: Unsuccessful response status code. Request failed with status code 404'

对这个问题的粗略搜索似乎没有返回任何与我想要完成的任务相关的内容,所以我回到了原点。

Cri*_*yne 7

我认为你最初的假设是正确的!如果您仍然需要指定范围,Workload Identity 将无法正常工作。在您链接的工作负载文章中,未使用范围。

我一直在努力解决同样的问题,并确定了三种在 Pod 中获取经过身份验证的凭据的方法。


1. Workload Identity(基本上是上面的 Workload Identity 文章,添加了一些部署详细信息)

此方法是首选方法,因为它允许集群中的每个 pod 部署仅被授予其所需的权限。

创建集群(注意:未定义范围或服务帐户)

gcloud beta container clusters create {cluster-name} \
  --release-channel regular \
  --identity-namespace {projectID}.svc.id.goog

Run Code Online (Sandbox Code Playgroud)

然后创建 k8sServiceAccount、分配角色并进行注释。

gcloud container clusters get-credentials {cluster-name}

kubectl create serviceaccount --namespace default {k8sServiceAccount}

gcloud iam service-accounts add-iam-policy-binding \
  --member serviceAccount:{projectID}.svc.id.goog[default/{k8sServiceAccount}] \
  --role roles/iam.workloadIdentityUser \
  {googleServiceAccount}

kubectl annotate serviceaccount \
  --namespace default \
  {k8sServiceAccount} \
  iam.gke.io/gcp-service-account={googleServiceAccount}
Run Code Online (Sandbox Code Playgroud)

然后我创建部署并设置 k8sServiceAccount。(设置服务帐户是我缺少的部分)

kubectl create deployment {deployment-name} --image={containerImageURL}
kubectl set serviceaccount deployment {deployment-name} {k8sServiceAccount}
Run Code Online (Sandbox Code Playgroud)

然后以8080为目标进行曝光

kubectl expose deployment {deployment-name}  --name={service-name} --type=LoadBalancer --port 80 --target-port 8080
Run Code Online (Sandbox Code Playgroud)

需要为 googleServiceAccount 分配适当的 IAM 角色(见下文)。


2. 集群服务帐号

此方法不是首选方法,因为集群中的所有 VM 和 Pod 都将具有基于定义的服务帐户的权限。

使用分配的服务帐户创建集群

gcloud beta container clusters create [cluster-name] \
 --release-channel regular \
 --service-account {googleServiceAccount}
Run Code Online (Sandbox Code Playgroud)

需要为 googleServiceAccount 分配适当的 IAM 角色(见下文)。

然后如上部署并公开,但不设置 k8sServiceAccount


3.范围

此方法不是首选方法,因为集群中的所有 VM 和 Pod 都将具有基于定义的范围的权限。

创建具有指定范围的集群(firestore只需要“cloud-platform”,实时数据库还需要“userinfo.email”)

gcloud beta container clusters create $2 \
  --release-channel regular \
  --scopes https://www.googleapis.com/auth/cloud-platform,https://www.googleapis.com/auth/userinfo.email

Run Code Online (Sandbox Code Playgroud)

然后如上部署并公开,但不设置 k8sServiceAccount


前两种方法需要分配了适当的 IAM 角色的 Google 服务帐户。以下是我为让一些 Firebase 产品正常运行而分配的角色:

  • FireStore:云数据存储用户(数据存储)
  • 实时数据库:Firebase 实时数据库管理(Firebase 产品)
  • 存储:存储对象管理(云存储)