简体   繁体   English

生成预签名的S3 URL时如何利用AWS Signature v4?

[英]How do I utilize AWS Signature v4 when generating a presigned S3 URL?

I'm inheriting a codebase that makes use of the Java AWS SDK to generate presigned S3 URLs for both Putting and Getting Objects. 我继承了一个利用Java AWS开发工具包生成用于放置和获取对象的预签名S3 URL的代码库。 The code looks something like this: 代码看起来像这样:

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

And this existing codebase has always worked, and is very close to working. 这个现有的代码库一直有效,并且非常接近有效。 However, one business requirement that changed is that we need to encrypt the contents of the S3 bucket. 但是,一项已更改的业务需求是我们需要对S3存储桶的内容进行加密。 So, naturally, I set the default encryption on the bucket to AWS-KMS (since it seemed like the most modern) and choose the default "aws/s3" key that had been created for my account. 因此,自然地,我将存储桶上的默认加密设置为AWS-KMS(因为它看起来是最现代的),然后选择为我的账户创建的默认“ aws / s3”密钥。

However, now when an end user tries to actually utilize the URLs I generate in their browser, this is the error message that appears: 但是,现在当最终用户尝试实际使用我在其浏览器中生成的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>

My question is utlimately: how do I get this working again? 我的问题是无条件的:如何使它重新工作? As I see it there are two different paths I could take. 在我看来,我可以采取两种不同的方法。 Either: 1) I could downgrade the bucket encryption from AWS-KMS to AES-256 and hope that it all works, or 2) I can make some change to my client code to support KMS, which I'm guessing would probably involve downloading the KMS key through the AWS SDK and using it to sign the requests, and possibly also adding some Authorization and other headers. 或者:1)我可以将存储桶加密从AWS-KMS降级到AES-256,并希望它能全部工作,或者2)我可以对客户端代码进行一些更改以支持KMS,我猜测这可能涉及下载通过AWS开发工具包使用KMS密钥并使用它来签名请求,还可能添加一些Authorization和其他标头。

Option 1 seems like less work but also less ideal, because who knows if a less secure form of encryption will always be supported. 选项1看起来工作量较少,但也不太理想,因为谁知道始终将支持安全性较低的加密形式。 And Option 2 seems like the better choice conceptually, but also raises some concerns because it does seem like a lot more work and I'm worried about having to include extra headers. 从概念上讲,选项2似乎是更好的选择,但同时也引起了一些担忧,因为它似乎还有很多工作要做,我担心必须包含额外的标题。 The code I've shown above reflects the equivalent of a PutObject request (proxied through the generated URL), but there are also equivalents of GetObject requests to download the images, which are possibly rendered directly in the browser. 我上面显示的代码反映了PutObject请求的等效项(通过生成的URL代理),但是也有等效的GetObject请求来下载图像,这些请求可能直接在浏览器中呈现。 It would be a lot harder to write frontend code there to use different headers just to render an image. 在其中编写前端代码以使用不同的标头仅用于渲染图像会更加困难。 (I wonder if query parameters can be substituted for headers?) (我想知道查询参数是否可以代替标题?)

Anyways, what would I need to change in my Java to get this working with AWS KMS? 无论如何,我需要在Java中进行哪些更改才能使其与AWS KMS一起使用? Do I need to use the AWS SDK to "download" the KMS key first as I suspected? 我怀疑是否需要使用AWS开发工具包先“下载” KMS密钥? And should I go about doing it that way, or would AES-256 really be the better option? 我应该那样做,还是AES-256真的是更好的选择?

Signing signature verion 4 has been the default for several years. 签名签名版本4已成为默认设置多年。 Unless you are overriding the signature in your AWS SDK profile, then you are using version 4. You can override this using the following code: 除非您在AWS开发工具包配置文件中覆盖签名,否则您将使用版本4。您可以使用以下代码覆盖此版本:

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

Most likely the real issue is that you need to specify server side encryption when you create the presigned URL. 真正的问题很可能是在创建预签名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);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM