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

Authenticating to Google Cloud Firestore from GKE with Workload Identity

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

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

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

因此,在本地,我的代码运行良好。我可以访问我的 Firestore 并做我需要做的一切。但是,一旦我部署到GKE,问题就出现了。

我按照这个 Google Documentation 为我的集群设置了一个工作负载身份,我已经创建了一个部署并通过 [=50 验证 pods 所有人都在使用正确的 IAM 服务帐户=]:

kubectl exec -it POD_NAME -c CONTAINER_NAME -n NAMESPACE sh
> gcloud auth list

文档给我的印象是,只要上述条件成立,我的服务就会进行身份验证。我真的不确定为什么,但我的 Firestore() 实例表现得好像它没有访问 Firestore 的必要凭据。

以下是我对实例的声明和实现,以防万一:

const firestore = new Firestore()

const server = new ApolloServer({
  schema: schema,
  dataSources: () => {
    return {
      userDatasource: new UserDatasource(firestore)
    }
  }
})

更新:

在一阵绝望中,我决定拆除一切并重建它。一步一步地完成所有事情后,我似乎遇到了一个错误,或者(更有可能)我第一次做错了一些事。我现在可以连接到我的后端服务。 但是,我现在遇到了不同的错误。发送任何请求后(我使用的是 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'

粗略搜索这个问题似乎return 与我要完成的事情没有任何关系,所以我回到原点。

即将结束这个问题。

以防万一有人无意中发现它,这就是为我修复它的方法。

1.) 我重新按照上面 Google 文档 link 中的步骤进行操作,这解决了我的 pods 无法启动的问题。

2.) 至于我的更新,我重新创建了我的集群并赋予它云数据源权限。我曾假设权限与 Workload Identity 运行所需的权限是分开的。我错了

我希望这对某人有所帮助。

我认为你最初的假设是正确的!如果您仍然必须指定范围,则 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

然后创建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}

然后我创建部署,设置 k8sServiceAccount。 (设置服务帐户是我遗漏的部分)

kubectl create deployment {deployment-name} --image={containerImageURL}
kubectl set serviceaccount deployment {deployment-name} {k8sServiceAccount}

然后以8080为目标暴露

kubectl expose deployment {deployment-name}  --name={service-name} --type=LoadBalancer --port 80 --target-port 8080

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


2。群集服务帐户

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

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

gcloud beta container clusters create [cluster-name] \
 --release-channel regular \
 --service-account {googleServiceAccount}

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

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


3。范围

这种方法不是首选,因为集群中的所有 VM 和 pods 都将根据定义的范围具有权限。

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

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

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


前两种方法需要一个 Google 服务帐户,并分配了适当的 IAM 角色。以下是我分配给一些 Firebase 产品的角色:

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