GCP存储-未提供签名密钥

时间:2020-11-12 20:44:26

标签: google-cloud-platform google-cloud-storage gcloud gsutil

即使我在这里找到了类似的问题:

Signing key was not provided and could not be derived on google precondition

这不会解决我的问题。

我正在本地验证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()))
    }

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

    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()

我得到signing key not provided

我发现很难识别出我真正想念的是什么。我已通过gcloud auth application-default login用户的owner身份验证,通常可以执行任何gcloud任务。这里有什么区别?

1 个答案:

答案 0 :(得分:3)

要签名,您需要一个私钥。拥有用户凭证就不能了,因为您的环境中只有一个刷新令牌。但是,在服务帐户密钥文件中,您具有私钥。您可以下载并使用它,但是出于安全原因,我不喜欢它。

wrote an article and I found a workaround in Python。我用Java建立了一个类似的技巧(对不起,我不是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)
  )
);

ImpersonatedCredentials仅在此处使用sign method in the class。如我的文章所述,此符号方法使用的是IAMUtils.signcall the Service Account Credential API方法。

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