gsutil 和存储客户端之间对存储桶子文件夹的访问不一致

Inconsistent access to subfolder of a bucket between gsutil and storage Client

为了避免为从许多设备接收到的数据管理大量存储桶,我计划让他们将捕获的文件写入单个存储桶的文件夹中,而不是每个设备一个存储桶。

为了确保每个设备只能写入其子文件夹,我将IAM条件设置为described in this answer:

resource.name.startsWith('projects/_/buckets/dev_bucket/objects/test_folder')

我的服务帐户现在具有附加了上述条件的 Storage Object CreatorStorage Object viewer 角色。

这是 gcloud get-iam-policy <project> 命令

的(仅截断到此服务帐户的)输出
- condition:
    expression: |-
      resource.name.startsWith("projects/_/buckets/dev_bucket/objects/test_folder/")
    title: only_test_subfolder
  members:
  - serviceAccount:myserviceaccount.iam.gserviceaccount.com
  role: roles/storage.objectCreator
- condition:
    expression: |-
      resource.name.startsWith("projects/_/buckets/dev_bucket/objects/test_folder/")
    title: only_test_subfolder
  members:
  - serviceAccount:myserviceaccount.iam.gserviceaccount.com
  role: roles/storage.objectViewer

当使用 gsutil 命令时,一切似乎都正常

# Set the authentication via the service account json key
gcloud auth activate-service-account --key-file=/path/to/my/key.json

# all of these commands work fine
gcloud ls gs://dev_bucket/test_folder 
gcloud cp gs://dev_bucket/test_folder/distant_file.txt local_file.txt

# These ones get a 403 as expected
gcloud ls gs://dev_bucket/
gcloud ls gs://another_bucket
gcloud_cp gs://dev_bucket/another_subfolder/somefile.txt local_file.txt

但是,当我尝试使用 google 存储客户端 (v 2.1.0) 时,我无法让它工作,主要是因为我应该在获取对象之前定义存储桶桶.

import os 
from google.cloud import storage
os.environ["GOOGLE_APPLICATION_CREDENTIALS"]="path/to/my/key.json"

client = storage.Client()

client.get_bucket("dev_bucket")

>>> Forbidden: 403 GET https://storage.googleapis.com/storage/v1/b/dev_bucket?projection=noAcl&prettyPrint=false: <Service account> does not have storage.buckets.get access to the Google Cloud Storage bucket.

我也曾尝试使用前缀参数列出所有文件,但得到了同样的错误:

client.list_blobs("dev_bucket", prefix="test_folder")

有没有办法使用具有此类权限的 python 存储客户端?

这是预期的行为!

您正在做:

gsutil ls gs://dev_bucket/test_folder 
gsutil cp gs://dev_bucket/test_folder/distant_file.txt local_file.txt

除了您的 SA 从角色 Storage Object viewer

获得的 storage.objects.get 之外,这两个命令不需要任何其他权限

但是 在你的代码中你试图访问存储桶的详细信息(存储桶本身,而不是存储桶内的对象)所以它不会工作,除非你的 SA 有权限storage.buckets.get

这一行:

client.get_bucket("dev_bucket")

将在 v1/buckets/get 上执行 GET 方法,这需要上述 IAM 权限。

因此,您需要修改代码以仅读取对象而不访问存储桶详细信息。

Here 是从存储桶下载对象的示例代码。

注意:此示例代码中使用的方法 bucket(bucket_name, user_project=None) 不会执行任何引用自 docs.

的 HTTP 请求

This will not make an HTTP request; it simply instantiates a bucket object owned by this client.


顺便说一句,您可以尝试 运行 类似的东西:

gsutil ls -L -b gs://dev_bucket

我希望此命令给您带来与您从代码中得到的相同的错误。


参考文献:

https://cloud.google.com/storage/docs/access-control/iam-gsutil https://cloud.google.com/storage/docs/access-control/iam-json