问题描述
我正在尝试使用Axios客户端在Node.js应用程序中获取Google云存储(GCS)的图像文件。在使用PC的开发模式下,我传递了Bearer令牌,并且所有令牌都能正常工作。
但是,我需要在Google Kubernetes Engine(GKE)托管的群集中的生产环境中使用它。
我制作了推荐的教程来创建服务帐户(GSA),然后通过工作负载标识方法为kubernetes帐户(KSA)锦上添花,但是当我尝试通过我的应用程序上的一个端点获取文件时,我收到了: / p>
{"statusCode":401,"message":"Unauthorized"}
缺少什么?
更新:我做了什么:
- 创建Google服务帐户
https://cloud.google.com/iam/docs/creating-managing-service-accounts
- 创建Kubernetes服务帐户
# gke-access-gcs.ksa.yaml file
apiVersion: v1
kind: ServiceAccount
Metadata:
name: gke-access-gcs
kubectl apply -f gke-access-gcs.ksa.yaml
- 与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
kubectl annotate serviceaccount \
--namespace k8s_namespace \
ksa_name \
iam.gke.io/gcp-service-account=gsa_name@gsa_project.iam.gserviceaccount.com
- 设置读写角色:
gcloud projects add-iam-policy-binding project-id \
--member=serviceAccount:[email protected] \
--role=roles/storage.objectAdmin
- 测试访问权限:
kubectl run -it \
--image google/cloud-sdk:slim \
--serviceaccount ksa-name \
--namespace k8s-namespace \
workload-identity-test
以上命令正常工作。请注意,已传递--serviceaccount
和workload-identity
。这对GKE是必要的吗?
PS:我不知道这是否会造成影响,但是我在项目中使用带代理的sql Cloud。
解决方法
编辑
问题中描述的问题与axios客户端不使用 Workload Identity利用的应用程序默认凭据(作为官方Google库)机制有关。 ADC检查:
- 如果设置了环境变量
GOOGLE_APPLICATION_CREDENTIALS
,则ADC将使用该变量指向的服务帐户文件。- 如果未设置环境变量
GOOGLE_APPLICATION_CREDENTIALS
,则ADC使用Compute Engine,Google Kubernetes Engine,App Engine,Cloud Run和Cloud Functions提供的默认服务帐户。
这意味着axios客户端将需要使用Bearer token
身份验证方法来针对Google Cloud Storage进行身份验证。
在官方文档中描述了对Bearer token
的身份验证:
API身份验证
要使用OAuth 2.0向Cloud Storage XML API或JSON API发出请求,请在每个需要身份验证的请求的
Authorization
标头中包含应用程序的访问令牌。您可以从OAuth 2.0 Playground生成访问令牌。Authorization: Bearer OAUTH2_TOKEN
以下是列出存储桶中对象的请求示例。
使用对象资源的list方法。
GET /storage/v1/b/example-bucket/o HTTP/1.1 Host: www.googleapis.com Authorization: Bearer ya29.AHES6ZRVmB7fkLtd1XTmq6mo0S1wqZZi3-Lh_s-6Uw7p8vtgSwg
我包括了使用Axios查询Cloud Storage(需要$ 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官方库代码段的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
这只是示例 - 名为“
bucket-namespace
”的Kubernetes命名空间 - 名为“
bucket-service-account
”的Kubernetes服务帐户 - 名为
google-bucket-service-account
的Google服务帐户 - 名称为
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!