【问题标题】:How to access Files in Google Cloud Storage through GKE pods如何通过 GKE pod 访问 Google Cloud Storage 中的文件
【发布时间】:2020-08-31 04:30:53
【问题描述】:

我正在尝试使用 Axios 客户端在我的 Node.js 应用程序中获取 Google Cloud Storage (GCS) 的图像文件。在使用我的 PC 的开发模式下,我传递了一个承载令牌并且一切正常。

但是,我需要在 Google Kubernetes Engine (GKE) 上托管的集群中的生产环境中使用它。

我做了推荐的教程来创建一个服务帐户 (GSA),然后我通过工作负载身份方法使用 kubernetes 帐户 (KSA),但是当我尝试通过我的应用程序上的一个端点获取文件时,我收到:

{"statusCode":401,"message":"Unauthorized"}

缺少什么?


更新:我做了什么:

  1. 创建 Google 服务帐户

https://cloud.google.com/iam/docs/creating-managing-service-accounts

  1. 创建 Kubernetes 服务帐号
# gke-access-gcs.ksa.yaml file

apiVersion: v1
kind: ServiceAccount
metadata:
  name: gke-access-gcs
kubectl apply -f gke-access-gcs.ksa.yaml
  1. 关联 KSA 和 GSA
gcloud iam service-accounts add-iam-policy-binding \
  --role roles/iam.workloadIdentityUser \
  --member "serviceAccount:cluster_project.svc.id.goog[k8s_namespace/ksa_name]" \
  gsa_name@gsa_project.iam.gserviceaccount.com
  1. 记下 KSA 并完成 KSA 和 GSA 之间的链接
kubectl annotate serviceaccount \
  --namespace k8s_namespace \
   ksa_name \
   iam.gke.io/gcp-service-account=gsa_name@gsa_project.iam.gserviceaccount.com
  1. 设置读写角色:
gcloud projects add-iam-policy-binding project-id \
--member=serviceAccount:gsa-account@project-id.iam.gserviceaccount.com \
--role=roles/storage.objectAdmin
  1. 测试访问:
kubectl run -it \
  --image google/cloud-sdk:slim \
  --serviceaccount ksa-name \
  --namespace k8s-namespace \
  workload-identity-test

上面的命令可以正常工作。请注意,已通过 --serviceaccountworkload-identity。这对 GKE 有必要吗?

PS:我不知道这是否有影响,但我在项目中使用的是带有代理的 SQL Cloud。

【问题讨论】:

  • 您需要获得授权才能访问云存储中的文件,除非这些文件是公开可用的。以前,您将创建一个服务帐户并将其下载为 json,您可以将其包含在 Kubernetes 机密 (cloud.google.com/kubernetes-engine/docs/tutorials/…) 中,但目前推荐的方法是工作负载身份cloud.google.com/kubernetes-engine/docs/how-to/…
  • 如果您在 GKE 上,请勿使用服务帐号密钥文件,请使用工作负载身份!
  • 另外,未经授权的权限在哪里?在你的豆荚里面?或者到达你的吊舱?
  • 我正在使用工作负载标识方法。当我访问一个使用 Axios 的端点时显示未经授权的权限消息(尝试从 GCS 获取图像)
  • 您使用过用户keni提供的指南吗?您能否说出您遵循哪个指南/教程/网站来达到这一点?您能否提供您在其他方面遵循的步骤?

标签: node.js kubernetes axios google-cloud-storage google-kubernetes-engine


【解决方案1】:

编辑

问题中描述的问题与 axios 客户端不使用Workload Identity 利用的应用程序默认凭据(作为官方 Google 库)机制有关。 ADC 检查:

  • 如果设置了环境变量GOOGLE_APPLICATION_CREDENTIALS,ADC 将使用该变量指向的服务帐户文件。
  • 如果未设置环境变量 GOOGLE_APPLICATION_CREDENTIALS,ADC 将使用 Compute Engine、Google Kubernetes Engine、App Engine、Cloud Run 和 Cloud Functions 提供的默认服务帐号。

-- Cloud.google.com: Authentication: Production

这意味着 axios 客户端需要回退到 Bearer token 身份验证方法才能针对 Google Cloud Storage 进行身份验证。

Bearer token的认证在官方文档中描述如下:

API 认证

要使用 OAuth 2.0 向 Cloud Storage XML APIJSON API 发出请求,请在每个需要身份验证的请求的 Authorization 标头中包含应用程序的访问令牌。您可以从OAuth 2.0 Playground 生成访问令牌。

Authorization: Bearer OAUTH2_TOKEN

以下是列出存储桶中对象的请求示例。

JSON API

使用 Objects 资源的list 方法。

GET /storage/v1/b/example-bucket/o HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer ya29.AHES6ZRVmB7fkLtd1XTmq6mo0S1wqZZi3-Lh_s-6Uw7p8vtgSwg

-- Cloud.google.com: Storage: Docs: Api authentication


我已经包含了一个使用 Axios 查询云存储的代码 sn-p 的基本示例(需要 $ npm install axios):

const Axios = require('axios');

const config = {
    headers: { Authorization: 'Bearer ${OAUTH2_TOKEN}' }
};

Axios.get( 
  'https://storage.googleapis.com/storage/v1/b/BUCKET-NAME/o/',
  config
).then(
  (response) => {
    console.log(response.data.items);
  },
  (err) => {
    console.log('Oh no. Something went wrong :(');
    // console.log(err) <-- Get the full output!
  }
);

我在下面留下了带有 node.js 官方库代码 sn-p 的 Workload Identity 设置示例,因为它可能对其他社区成员有用。


在我设法使用Workload Identity 和一个简单的nodejs 应用程序从GCP bucket 发送和检索数据时发布此答案。

我包含了一些用于解决潜在问题的要点。


步骤:

  • 检查GKE 集群是否启用了Workload Identity
  • 检查您的Kubernetes service account 是否与您的Google Service account 相关联。
  • 检查示例工作负载在连接到 API 时是否使用正确的 Google Service account
  • 检查您的Google Service account 是否具有访问bucket 的正确权限。

你也可以关注官方文档:


假设:

  • 项目 (ID) 名称:awesome-project 只是示例
  • Kubernetes 命名空间命名:bucket-namespace
  • Kubernetes 服务帐号名为:bucket-service-account
  • Google 服务帐户名为:google-bucket-service-account
  • 云存储桶名为:workload-bucket-example 只是示例

我已经包含了命令:

$ kubectl create namespace bucket-namespace
$ kubectl create serviceaccount --namespace bucket-namespace bucket-service-account
$ gcloud iam service-accounts create google-bucket-service-account
$ gcloud iam service-accounts add-iam-policy-binding --role roles/iam.workloadIdentityUser --member "serviceAccount:awesome-project.svc.id.goog[bucket-namespace/bucket-service-account]" google-bucket-service-account@awesome-project.iam.gserviceaccount.com
$ kubectl annotate serviceaccount --namespace bucket-namespace bucket-service-account iam.gke.io/gcp-service-account=google-bucket-service-account@awesome-project-ID.iam.gserviceaccount.com

使用上面链接的指南检查对 API 进行身份验证的服务帐户:

  • $ kubectl run -it --image google/cloud-sdk:slim --serviceaccount bucket-service-account --namespace bucket-namespace workload-identity-test

$ gcloud auth list 的输出应该显示:

                           Credentialed Accounts
ACTIVE  ACCOUNT
*       google-bucket-service-account@AWESOME-PROJECT.iam.gserviceaccount.com

To set the active account, run:
    $ gcloud config set account `ACCOUNT`

之前创建的 Google 服务帐户应该出现在输出中!

还需要将服务帐户的权限添加到存储桶。您可以:

  • 使用Cloud Console
  • 运行:$ gsutil iam ch serviceAccount:google-bucket-service-account@awesome-project.iam.gserviceaccount.com:roles/storage.admin gs://workload-bucket-example

要从workload-bucket-example 下载文件,可以使用以下代码:

// Copyright 2020 Google LLC

/**
 * This application demonstrates how to perform basic operations on files with
 * the Google Cloud Storage API.
 *
 * For more information, see the README.md under /storage and the documentation
 * at https://cloud.google.com/storage/docs.
 */
const path = require('path');
const cwd = path.join(__dirname, '..');

function main(
  bucketName = 'workload-bucket-example',
  srcFilename = 'hello.txt',
  destFilename = path.join(cwd, 'hello.txt')
) {
  const {Storage} = require('@google-cloud/storage');

  // Creates a client
  const storage = new Storage();

  async function downloadFile() {
    const options = {
      // The path to which the file should be downloaded, e.g. "./file.txt"
      destination: destFilename,
    };

    // Downloads the file
    await storage.bucket(bucketName).file(srcFilename).download(options);

    console.log(
      `gs://${bucketName}/${srcFilename} downloaded to ${destFilename}.`
    );
  }

  downloadFile().catch(console.error);
  // [END storage_download_file]
}
main(...process.argv.slice(2));

代码完全复制自:

运行这段代码应该会产生一个输出:

root@ubuntu:/# nodejs app.js 
gs://workload-bucket-example/hello.txt downloaded to /hello.txt.
root@ubuntu:/# cat hello.txt 
Hello there!

【讨论】:

    猜你喜欢
    • 2021-06-16
    • 2021-07-20
    • 2019-01-16
    • 1970-01-01
    • 2019-07-25
    • 2020-11-23
    • 2018-12-25
    • 1970-01-01
    • 2016-08-19
    相关资源
    最近更新 更多