使用工作负载标识从GKE对Google Cloud Firestore进行身份验证

7

我想编写一个简单的后端,以访问我的Google Cloud Firestore,它位于Google Kubernetes引擎中。在本地,我使用以下代码进行身份验证,以便像Google文档中所述访问Firestore。

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

这会调用 GOOGLE_APPLICATION_CREDENTIALS 环境变量并使用我从创建具有 "Cloud Datastore User" 角色的服务帐户时获得的 google-application-credentals.json 来填充它。

因此,在本地,我的代码可以正常运行。我可以访问我的 Firestore 并且能够进行我需要的所有操作。然而,问题出现在我部署到 GKE 后。

我按照此 Google 文档 设置了我的集群的工作负载身份,创建了一个部署,并通过运行以下命令验证所有 pod 是否都在使用正确的 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错误。

检查日志会得到以下结果:

'尝试从插件获取元数据失败,出现错误:无法刷新访问令牌:在尝试检索计算引擎内置服务账户的访问令牌时返回了未找到的错误。这可能是因为计算引擎实例没有指定任何权限范围导致的:无法刷新访问令牌:响应状态码不成功。请求失败,状态代码为404'

对此问题进行简单的搜索似乎与我想要完成的任务无关,因此我又回到了起点。

2个回答

7

我认为您最初的假设是正确的!如果仍需指定作用域,则 Workload Identity 无法正常运行。在您链接的 Workload 文章中,未使用作用域。

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


1. 工作负载标识(基本上是上面链接的 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}

我创建我的部署(deployment)并设置了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和pod将基于定义的服务帐户拥有权限。

创建已分配服务账户的集群

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

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

接下来按照上述方式部署和公开,但是不需要设置k8sServiceAccount。


前两种方法需要拥有适当IAM角色的Google服务账号。以下是我指定的一些角色,以使一些Firebase产品正常工作:

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

感谢您深入的回复,比 Google 文档更有帮助。由于项目已经引导我走向不同的方向,我还没有尝试过这个方法,但是当我回到它时,如果它有效,我将把它作为被接受的答案 :)。谢谢! - James Williams
谢谢,这非常有帮助。我在工作负载身份验证方案中有一个场景,其中我有两个 KSA 绑定到两个不同的 Google SA,我该如何让我的部署同时使用这两个 KSA?因为下面的命令一次只能设置一个服务账号。 kubectl set serviceaccount deployment {deployment-name} {k8sServiceAccount} 非常感谢您的帮助。 - Nitin Rawat
你是在创建一个需要两组凭据的部署,还是需要两个各自需要不同凭据的部署?我相信单个部署只能有一个服务帐户,但是从同一映像创建的多个部署可以各自拥有自己的服务帐户。 - CrispyDyne

2

我将关闭这个问题。

万一有人偶然看到它,这是我解决它的方法:

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

2.) 至于我的更新,我重新创建了我的集群,并赋予它Cloud数据源权限。我一直认为权限与工作负载身份所需的权限不同。我错了。

希望这能帮助到某人。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接