【问题标题】:How do I utilize AWS Signature v4 when generating a presigned S3 URL?在生成预签名 S3 URL 时如何使用 AWS Signature v4?
【发布时间】:2018-04-30 06:20:08
【问题描述】:

我正在继承一个代码库,该代码库利用 Java AWS 开发工具包生成用于放置和获取对象的预签名 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 开发工具包获取 KMS 密钥并使用它对请求进行签名,还可能添加一些 Authorization 和其他标头。

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

无论如何,我需要在我的 Java 中进行哪些更改才能使其与 AWS KMS 一起使用?我是否需要像我怀疑的那样首先使用 AWS 开发工具包“下载”KMS 密钥?我应该这样做吗,还是 AES-256 真的是更好的选择?

【问题讨论】:

标签: java amazon-web-services encryption amazon-s3 aws-kms


【解决方案1】:

签名签名版本 4 多年来一直是默认设置。除非您在 AWS 开发工具包配置文件中覆盖签名,否则您使用的是版本 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);

【讨论】:

  • 是的,但是如何检索myKey 的值?当我在 S3 控制台中对存储桶设置加密时,我只是选择了默认/预先创建的 KMS 密钥。我需要使用什么客户端代码?
  • mykey 是代码中的文件名,而不是 KMS 密钥。 S3 存储桶是平面的,对象(文件名)称为键。 Key – 您分配给对象的名称。您使用对象键来检索或放置对象。
  • 我包含了与 KMS SSE 交互的代码。查看 withSSEAlgorithm() 的文档。 docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/…
  • 试过了,但现在我收到一个 XML 错误,上面写着“我们计算的请求签名与您提供的签名不匹配。请检查您的密钥和签名方法”
  • 有趣的是,当我使用 CLI 时,我可以通过首先调用 aws configure set default.s3.signature_version s3v4 然后调用 aws s3 presign bucket/filename.jpg 并且该 URL 有效来生成预签名 URL。但是,当我使用上面的代码时,它不起作用。我在两个 URL 之间看到的唯一可观察到的区别是 CLI 将 X-Amz-SignedHeaders 标头值设置为 host 而您的代码将其设置为 content-type;host;x-amz-server-side-encryption 有什么想法吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-14
  • 2018-02-02
  • 2023-01-19
  • 2020-06-06
  • 2017-07-21
相关资源
最近更新 更多