GCP 存储 - 未提供签名密钥

Voj*_*ěch 3 google-cloud-storage gsutil google-cloud-platform gcloud

尽管我在这里发现了类似的问题:

未提供签名密钥,且无法在 google 前提条件下派生

这不会解决我的问题。

我在本地对 Google Storage 默认服务帐户进行身份验证,我可以轻松读取存储桶对象,如下所示:

    private val storage: Storage = StorageOptions
        .newBuilder()
        .setProjectId(projectId)
        .build()
        .service

    fun read() {
        val blob = storage
            .get(BlobId.of(bucket, object))

        println(String(blob.getContent()))
    }
Run Code Online (Sandbox Code Playgroud)

但是,当我尝试使用以下命令生成签名的上传网址时:

    fun uploadUrl(objectName: String): String = storage
        .signUrl(
            BlobInfo.newBuilder(BlobId.of(bucketName, objectName)).build(),
            15,
            TimeUnit.MINUTES,
            Storage.SignUrlOption.httpMethod(HttpMethod.PUT),
            Storage.SignUrlOption.withExtHeaders(mapOf("Content-Type" to "application/octet-stream")),
            Storage.SignUrlOption.withV4Signature()
        )
        .toString()
Run Code Online (Sandbox Code Playgroud)

我正进入(状态signing key not provided

我发现很难认识到我到底错过了什么。我已通过用户身份验证gcloud auth application-default loginowner通常允许我执行任何 gcloud 任务。这里有什么区别呢?

gui*_*ere 6

要签署某些内容,您需要私钥。对于用户凭据,您不能这样做,因为您的环境中只有一个刷新令牌。但是,在服务帐户密钥文件中,您有一个私钥。您可以下载并使用它,但出于安全原因我不喜欢它。

写了一篇文章,并在 Python 中找到了解决方法。我在 Java 中构建了一个类似的 hack(抱歉,我不是 kotlin 开发人员!但我确信每个都可以转换!)。

Storage storage = StorageOptions.getDefaultInstance().getService();

Credentials credentialsToSIgn = storage.getOptions().getCredentials();
if (credentialsToSIgn instanceof UserCredentials) {
  credentialsToSIgn = ImpersonatedCredentials.create(
    (GoogleCredentials) credentialsToSIgn,
    "SERVICE_ACCOUNT_EMAIL",
    Collections.EMPTY_LIST, 
    Collections.EMPTY_LIST, 
    3600);
}
System.out.println(
  storage.signUrl(
    BlobInfo.newBuilder(BlobId.of(bucketName, objectName)).build(),
    15,
    TimeUnit.MINUTES,
    Storage.SignUrlOption.httpMethod(HttpMethod.PUT),
    Storage.SignUrlOption.withExtHeaders(mapOf("Content-Type" to "application/octet-stream")),
    Storage.SignUrlOption.withV4Signature()
    Storage.SignUrlOption.signWith((ServiceAccountSigner) credentialsToSIgn)
  )
);
Run Code Online (Sandbox Code Playgroud)

ImpersonatedCredentials在这里只是为了使用类中的sign方法。此签名方法使用IAMUtils.sign方法,该方法调用服务帐户凭据 API,如我的文章中所述

这不是一个很好的技巧,但它确实有效。您可以将服务帐户电子邮件放入参数中,并在本地环境之外将其省略,以确保不会在其他地方执行错误的操作。