当前位置: 首页 > 知识库问答 >
问题:

服务号Java的Google Cloud Storage-403 Caller没有storage.objects.list访问存储桶

施海
2023-03-14

我们想从应用服务器的Google存储中下载文件。重要的是对单个bucket进行只读限制访问,而不是其他内容。

起初,我使用了一个普通用户帐户(不是服务帐户),该帐户有权访问我们谷歌云项目中的所有bucket,一切正常——我的Java代码打开bucket并下载文件时没有出现问题。

Storage storage = StorageOptions.getDefaultInstance().getService();
Bucket b = storage.get( "mybucketname" );

然后我想切换到使用一个专门创建的服务帐户,该帐户只能访问单个bucket。因此,我创建了一个服务帐户,授予读取单个bucket的权限,并下载了它的密钥文件。Google云控制台中的权限命名为:

存储对象查看器(3个成员)对GCS对象的读取权限。

Gsutil命令行实用程序可以很好地使用此帐户-从命令行它允许访问此存储桶,但不允许访问其他存储桶。

命令行的初始化使用以下命令完成:

gcloud --project myprojectname auth activate-service-account files-viewer2@myprojectname.iam.gserviceaccount.com --key-file=/.../keyfilename.json

我甚至尝试了两个不同的服务帐户,它们可以访问不同的bucket,我可以从命令行在它们之间切换,而gsutil只允许访问相关的bucket,对于任何其他bucket,它都会返回错误:

“AccessDeniedException:403调用方没有对存储桶xxxxxxxxx的storage.objects.list访问权限。”

因此,从命令行来看,一切都很顺利。但在Java中,身份验证存在一些问题。

我以前用于常规用户帐户的默认身份验证已停止工作-它报告错误:

com.google.云存储StorageException:匿名用户没有存储。铲斗。访问存储桶xxxxxxxxx。

然后,我尝试了以下代码(这是最简单的变体,因为它依赖于关键的json文件,但我已经尝试了在各种论坛中找到的许多其他变体,但没有成功):

FileInputStream fis = new FileInputStream( "/path/to/the/key-file.json" );
ServiceAccountCredentials credentials = ServiceAccountCredentials.fromStream( fis );
Storage storage = StorageOptions.newBuilder().setCredentials( credentials )
    .setProjectId( "myprojectid" ).build().getService();
Bucket b = storage.get( "mybucketname" );

我收到的只是这个错误:

com.google.云存储StorageException:调用方没有存储。铲斗。获取bucket mybucketname的访问权限。原因:com.google.api。客户古格里皮斯。json。GoogleJsonResponseException:403禁止

无论我尝试访问哪个存储桶(即使不存在),都会返回相同的错误。让我困惑的是,使用相同的JSON密钥文件初始化的同一个服务帐户在命令行中运行良好。因此,我认为Java代码中缺少一些确保正确身份验证的东西。

共有2个答案

滕学义
2023-03-14

多亏了@Taxdude的详细解释,我理解了我的Java代码应该是正确的,并开始寻找导致该问题的其他可能原因。

我尝试过的另一件事是设置服务帐户的权限,在那里我找到了解决方案——实际上这是出乎意料的。

创建服务帐户时,不能授予其从Google存储读取的权限,因为这样它将拥有对所有存储桶的读取权限,并且无法更改该权限(不知道为什么),因为系统将这些权限标记为“继承”。

因此,您必须:

  • 创建一个没有权限的空白服务号,然后
  • 从存储桶配置配置权限

这样做:

  • 打开Google云Web控制
  • 打开存储浏览器
  • 选择您的铲斗
  • 使用权限打开信息面板
  • 添加具有Storage Object Viewer权限的服务帐户,但也有名为Storage Legacy Object Reader和Storage Legacy Bucket Reader的权限

由于“Legacy”这个词,我认为不应该使用它们——它们看起来像是为了向后兼容而保留的东西。在尝试并添加这些“遗留”权限之后,我一直在尝试的同一代码突然开始正常工作。

我仍然不能完全确定我应该为服务帐户分配的最小权限集是什么,但至少现在它可以处理bucket上的所有三个“读取”权限—两个“遗留”权限和一个“正常”权限。

仰雅昶
2023-03-14

TL;DR-如果您使用的是应用程序默认凭据(在执行存储选项时,请顺便说一句)。getDefaultInstance()。getService() ),如果需要使用服务帐户中的凭据,则无需更改代码即可使用。您只需将环境变量设置为服务帐户json文件的完整路径,即可完成所有设置。

>

Storage storage = StorageOptions.getDefaultInstance().getService();
Bucket b = storage.get( "mybucketname" );

将环境变量GOOGLE\u APPLICATION\u CREDENTIALS设置为包含服务帐户凭据的json文件的完整路径。

export GOOGLE_APPLICATION_CREDENTIALS=/path/to/service_account_credentials.json

再次运行java应用程序以验证其是否按预期工作。

您发布的用于初始化ServiceAccount t凭据的代码示例在我看来很有效。我尝试了以下代码片段,它按预期为我工作。

String SERVICE_ACCOUNT_JSON_PATH = "/path/to/service_account_credentials.json";

Storage storage =
    StorageOptions.newBuilder()
        .setCredentials(
            ServiceAccountCredentials.fromStream(
                new FileInputStream(SERVICE_ACCOUNT_JSON_PATH)))
        .build()
        .getService();
Bucket b = storage.get("mybucketname");

指定服务号凭据时,项目ID会自动从json文件中的信息中获取。因此您不必再次指定它。但我不完全确定这是否与您正在观察的问题有关。

以下是有关应用程序默认凭据的完整文档,解释了根据您的环境选择哪些凭据。

您可以通过进行单个客户端库调用来获取应用程序默认凭据。返回的凭据由代码运行的环境决定。按以下顺序检查条件:

>

  • 选中环境变量GOOGLE\u APPLICATION\u CREDENTIALS。如果指定了此变量,则应指向定义凭据的文件。为此目的获取凭据的最简单方法是在Google API控制台中创建服务帐户密钥:

    a、 转到API控制台凭据页面。

    b、 从项目下拉列表中,选择您的项目。

    c、 在凭据页面上,选择创建凭据下拉列表,然后选择服务帐户密钥。

    d、 从服务帐户下拉列表中,选择现有服务帐户或创建新的服务帐户。

    e、 对于键类型,选择JSON键选项,然后选择创建。该文件会自动下载到您的计算机。

    f、 放置*。您刚才下载的json文件位于您选择的目录中。此目录必须是私有的(您不能让任何人访问此目录),但可以访问您的web服务器代码。

    g.将环境变量GOOGLE_APPLICATION_CREDENTIALS设置为下载的JSON文件的路径。

    如果您在计算机上安装了Google CloudSDK并运行了命令gcloud auth Application-default login,您的身份可以用作代理来测试从该计算机调用API的代码。

    如果您正在运行Google App Engine产品,将使用与应用程序关联的内置服务帐户。

    如果您正在运行Google Compute Engine产品,则将使用与虚拟机实例关联的内置服务帐户。

    如果这些条件均不成立,则会发生错误。

    我建议查看云存储可用的IAM权限和IAM角色。这些提供了项目和铲斗级别的控制。此外,您可以使用ACL控制bucket中对象级别的权限。

    >

    如果您还想授予服务帐户获取(storage.objects.get)和列出(storage.objects.list)单个对象的权限,请同时添加角色/存储。objectViewer到服务帐户。

  •  类似资料:
    • 我想使用gsutil和服务帐户在命令行上访问Goolge播放报告。有一个云存储URI,格式为gs://bucket\u name,我可以用我的用户帐户列出和下载报告,但不能用我创建的服务帐户。错误总是相同的: 我已向服务帐户授予了所有必需的权限,因此我不明白为什么用户帐户可以使用,而服务帐户却无法使用。 所以如果你知道如何帮助我,我会非常感谢你。

    • 问题内容: 我们想从Google Storage中的应用服务器中下载文件。对单个存储桶进行只读受限访问很重要,而别无其他。 最初,我使用了普通用户帐户(而非服务帐户),该帐户具有访问Google Cloud项目中所有存储桶的权限,并且一切正常- 我的Java代码打开存储桶并下载文件没有问题。 然后,我想切换为使用专门创建的服务帐户,该帐户只能访问一个存储桶。因此,我创建了一个服务帐户,授予读取单个

    • 为了更清楚地说明,我明白最终必须有人被信任。例如,ops工程师可以拥有自己的凭据来访问Vault,并获得相同数据库的密码。这将允许用户访问,但不允许该用户模拟服务。是否有任何理由ops工程师也应该知道服务自己的凭据,以便在初始化后访问保险库?

    • 我正在尝试编写一个Java程序,将Vault导出数据下载到Google云存储桶中,因为导出数据在两周后被删除。Vault数据与典型的GCS存储桶和对象标识关联,因此可能存储在GCS中。似乎有两个Java客户端库,com。谷歌。云存储和com。谷歌。应用程序编程接口。服务。存储,它似乎完成了我需要的功能,但以不同的方式工作,并使用不同的身份验证源(凭据对象)。如果我使用com。谷歌。应用程序编程接口

    • 问题内容: 是否有人从Oracle存储过程成功访问了Web服务?如果是这样,那是Java存储过程吗?PL / SQL存储过程? 有什么原因为什么我不应该尝试从存储的proc访问WS? 这是我到目前为止发现的几个参考 数据库Web服务 从Java存储过程调用外部Web服务 为了澄清,这是针对SOAP调用的 问题答案: 首先,您要调用哪种Web服务?我假设是SOAP或REST。 对于REST Web服

    • 议程:在Linux和Windows之间有一个共同的项目文件夹 在我的ubuntu机器14.04中,我已将文档根目录从:更改为 我得到错误为: 被禁止的 您没有访问/此服务器的权限。 Apache/2.4。本地主机端口80上的7(Ubuntu)服务器 所以我添加了一些脚本到: 但是可以工作,但不适用于Windows NTFS分区驱动器。 即使在提到: 错误消息“禁止您没有访问/此服务器的权限” 我的