"Access Denied. Provided scope(s) are not authorized" 尝试使用 REST API 创建对象 public 时出错

"Access Denied. Provided scope(s) are not authorized" error when trying to make objects public using the REST API

我正在尝试为 Google Cloud Storage 存储桶中的单个对象设置权限,以便在 the steps indicated in Google's documentation 之后公开查看它们。当我尝试使用我们的应用程序服务帐户发出这些请求时,请求失败并显示 HTTP 状态 403 和以下消息:

Access denied. Provided scope(s) are not authorized.

其他请求工作正常。当我尝试做同样的事情但通过为我的个人帐户提供令牌时,对对象的 ACL 的 PUT 请求有效......大约 50% 的时间(其余时间它是 503 错误,可能相关也可能不相关)。

更改服务帐户的 IAM 策略以匹配我的 - 它通常具有 Storage Admin 和一些其他附带角色 - 没有帮助,即使我赋予它整体所有者 IAM 角色,这就是我所拥有的。

使用 XML API 和 JSON 版本都不一样。该请求有时会与我的个人凭据一起使用,这向我表明该请求的格式没有错误,但必须有其他我迄今为止忽略的东西。有什么想法吗?

如果您使用的是默认计算引擎服务帐户,请检查服务帐户的范围。默认情况下,范围是受限的,对于 GCS,它是只读的。在清除缓存的情况下使用 rm -r ~/.gsutil 清除缓存

按照您提供的 documentation 进行操作,同时考虑以下几点:

  • 存储桶的访问控制系统必须细粒度(不统一)。

  • 为了使对象 public 仅可用,请确保存储桶未启用 public 访问保护 。检查此 link 以获取更多信息。

  • 在存储桶中授予具有适当权限的服务帐户Storage Legacy Object Owner 角色 (roles/storage.legacyObjectOwner) 需要编辑对象 ACL,如 here 所示。可以为单个存储桶而非项目授予此角色。

  • 按照文档中的指示创建 json 文件。

  • 使用gcloud auth application-default print-access-token获取授权访问令牌并在API调用中使用它。 API 调用应如下所示:

curl -X POST --data-binary @JSON_FILE_NAME.json \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "Content-Type: application/json" \
  "https://storage.googleapis.com/storage/v1/b/BUCKET_NAME/o/OBJECT_NAME/acl"

您需要在创建实例时添加OAuth scope: cloud-platform。看:https://cloud.google.com/sdk/gcloud/reference/compute/instances/create#--scopes

select“允许完全访问所有云 API”或select细粒度方法

当尝试从 GCE 实例访问 GCS 并收到此错误消息时...
默认的 scopedevstorage.read_only,这会阻止所有写操作。

不确定是否需要范围 https://www.googleapis.com/auth/cloud-platform,默认情况下范围 https://www.googleapis.com/auth/devstorage.read_only(例如读取启动脚本)。范围应该是:https://www.googleapis.com/auth/devstorage.read_write.


并且可以使用 gcloud beta compute instances set-scopes 编辑实例的范围:

gcloud beta compute instances set-scopes $INSTANCE_NAME \
  --project=$PROJECT_ID \
  --zone=$COMPUTE_ZONE \
  --scopes=https://www.googleapis.com/auth/devstorage.read_write \
  --service-account=$SERVICE_ACCOUNT

也可以传递范围的所有已知别名,例如:--scopes=cloud-platform。由于权限原因,该命令必须 运行 在实例外部 - 并且必须关闭实例才能更改服务帐户。

因此,多年后,事实证明问题是 Google 云 API 使用“范围”来指代两个细微不同的事物。一个是服务帐户可用的可用权限范围,这是我(以及大多数其他回答该问题的人)一直关注的问题,但问题出在其他方面。 Python class google.auth.credentials.Credentials,被各种 Google 云客户端 class 用来进行身份验证, 具有权限范围用于 OAuth。您会看到这是怎么回事——我使用的客户端是使用 'https://www.googleapis.com/auth/devstorage.read_write' 的默认 OAuth 范围创建的,但是要创建 public 需要范围 'https://www.googleapis.com/auth/devstorage.full_control'。将此范围添加到 OAuth 凭据请求意味着设置 public 对象权限有效。