我正在开发一个将在 Google Cloud Run 上运行并将文件存储在 Google Cloud 存储中的程序。
我遇到的问题发生在尝试生成签名 URL 以从通常是私有的云存储中下载文件时。在我的本地机器上它可以正常工作,但在 Cloud Run 中运行时却不行。
我在本地使用已分配角色的服务帐户Storage Object Admin
。我使用名为的环境变量加载权限,GOOGLE_APPLICATION_CREDENTIALS
其值是我从云控制台下载的密钥 .json 文件的绝对路径。
在 Cloud Run 上,我向服务运行的服务帐户授予了相同的角色。但是,当我尝试在那里签署任何内容时,出现了异常:
java.io.IOException:错误代码 403 尝试签署提供的字节:调用者没有权限
在我的代码中,我没有明确选择任何服务帐户,因为 SDK 文档让我相信这是自动完成的。在 Cloud Run 中,我没有GOOGLE_APPLICATION_CREDENTIALS
设置变量,因为我认为这也是自动完成的。
令我困惑的是,在 Cloud Run 中运行的应用程序仍然可以正常将文件上传到 Cloud Storage,所以这让我认为它确实具有来自某处的某种形式的凭据。
我究竟做错了什么?
答案1
总结:确保服务帐户具有iam.serviceAccounts.signBlob
权限。
在进一步研究了我在 Cloud Run 上获取凭据的方法后:
GoogleCredentials credentials = ComputeEngineCredentials.create();
Storage storage = StorageOptions.newBuilder().setCredentials(credentials).build().getService();
我读过javadoc为了ComputeEngineCredentials
:
代表 Google Compute Engine VM 内置服务帐户的 OAuth2 凭据。从 Google Compute Engine 元数据服务器获取访问令牌。这些凭据使用 IAM API 签署数据。有关更多详细信息,请参阅 sign(byte[])。
在这之后我读了javadoc对于sign(byte[])
(强调我的):
使用与服务帐号关联的私钥对提供的字节进行签名。Compute Engine 的项目必须启用身份和访问管理 (IAM) API,并且实例的服务帐号必须具有iam.serviceAccounts.signBlob允许。
因此,我创建了一个仅具有iam.serviceAccounts.signBlob
权限的新角色,并将其分配给我的 Cloud Run 配置使用的服务帐号。此后,问题立即消失(无需重新部署)
答案2
此外,请确保您也已启用IAM Service Account Credentials API
此功能。