在生成预先签名的S3 URL时,如何使用AWS签名V4



我正在继承一个使用Java AWS SDK的代码库,以生成预先签名的S3 URL,以放置对象和获取对象。该代码看起来像这样:

GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucket, filename);
request.setMethod(HttpMethod.PUT);
request.setExpiration(new DateTime().plusMinutes(30).toDate());
request.setContentType("image/jpeg");
String url = awss3.generatePresignedUrl(request);

这个现有的代码库一直有效,并且非常接近工作。但是,更改的一个业务需求是我们需要对S3存储桶的内容进行加密。因此,自然地,我将默认加密设置为AWS-KMS(因为它似乎是最现代的(,并选择为我的帐户创建的默认" AWS/S3"键。

但是,现在,当最终用户尝试实际利用我在浏览器中生成的URL时,这是出现的错误消息:

<?xml version="1.0" encoding="UTF-8"?>
<Error>
  <code>InvalidArgument</code>
  <Message>Requests specifying Server Side Encryption with AWS KMS managed keys require AWS Signature Version 4.</Message>
  <ArgumentName>Authorization</ArgumentName>
  <ArgumentValue>null</ArgumentValue>
  <RequestId>...</RequestId>
  <HostId>...</HostId>
</Error>

我的问题是我的问题:我该如何再次工作?如我所见,我可以走两条不同的路径。要么:1(我可以将存储桶加密从AWS-KMS降级到AES-256,并希望一切都起作用,或者2(我可以对我的客户端代码进行一些更改以支持KMS,我猜这可能涉及下载通过AWS SDK的KMS键并使用它来签署请求,并可能添加一些授权和其他标题。

选项1似乎工作较少,但也不太理想,因为谁知道始终支持不太安全的加密形式。选项2在概念上似乎是更好的选择,但也引起了一些担忧,因为它确实做了更多的工作,我担心必须包括额外的标题。我上面显示的代码反映了putobject请求的等效(通过生成的URL代理(,但也有同等的getObject请求以下载图像,这些图像可能直接在浏览器中呈现。在此处编写前端代码来使用不同的标头只是为了渲染图像将很难。(我想知道是否可以将查询参数替换为标题?(

无论如何,我需要在Java上进行什么才能与AWS KMS合作?当我怀疑时,我是否需要使用AWS SDK首先"下载" KMS密钥?我应该这样做,还是AES-256确实是更好的选择?

签名签名方面4已有数年的默认值。除非您在AWS SDK配置文件中覆盖签名,否则您使用版本4。您可以使用以下代码覆盖此签名:

AmazonS3Client s3 = new AmazonS3Client(new  ClientConfiguration().withSignerOverride("AWSS3V4SignerType"));

很可能真正的问题是您需要在创建预先符号URL时指定服务器端加密。

GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(
    myBucket, myKey, HttpMethod.PUT)
    .withSSEAlgorithm(SSEAlgorithm.KMS.getAlgorithm());
request.setExpiration(new DateTime().plusMinutes(30).toDate());
request.setContentType("image/jpeg");
URL puturl = s3.generatePresignedUrl(request);

最新更新