【发布时间】: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 真的是更好的选择?
【问题讨论】:
-
您使用的是 ClientConfiguration().withSignerOverride("AWSS3V4SignerType"))。然后在调用 GeneratePresignedUrlRequest 时添加 .withSSEAlgorithm(SSEAlgorithm.KMS.getAlgorithm())。您还可以使用 .withKmsCmkId(id) docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/… 指定 KMS 密钥 ID
标签: java amazon-web-services encryption amazon-s3 aws-kms