AWS Developer Tools Blog

Generating Amazon S3 Pre-signed URLs with SSE-KMS (Part 2)

To continue from the previous blog, I will provide specific code examples that show how you can generate and consume pre-signed URLs using server-side encryption with AWS Key Management Service (SSE-KMS). A pre-requisite to this option is that you must be using Signature Version 4 (SigV4). You can enable SigV4 in the AWS SDK for Java in various ways, including using S3-specific system properties. Here, I will provide a less known but programmatic way to achieve that by explicitly configuring the signer. The code samples assume the version of the AWS SDK for Java to be 1.9.31 or later.

Configure AmazonS3Client to use SigV4

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

Once this is in place, you are good to go.

Server-Side Encryption with AWS Key Management Service (SSE-KMS)

Example A. Here’s how to generate a pre-signed PUT URL using SSE-KMS:

String myExistingBucket = ... // an existing bucket
String myKey = ...    // target S3 key
// Generate a pre-signed PUT URL for use with SSE-KMS
GeneratePresignedUrlRequest genreq = new GeneratePresignedUrlRequest(
    myExistingBucket, myKey, HttpMethod.PUT)
    .withSSEAlgorithm(SSEAlgorithm.KMS.getAlgorithm())
    ;
// s3 is assumed to have been configured to use SigV4
URL puturl = s3.generatePresignedUrl(genreq);
System.out.println("Presigned PUT URL with SSE-KMS: " + puturl);

In the above example, Amazon S3 will make use of the default KMS master key for S3 that is automatically created for you. (See Creating Keys in AWS Key Management Service for more information on how you can set up your AWS KMS customer master keys.)

However, you can also choose to explicitly specify your KMS customer master key id as part of the pre-signed URLs.

Example B. Here’s how to generate a pre-signed PUT URL using SSE-KMS with an explicit KMS customer master key id:


// Generate a pre-signed PUT URL for use with SSE-KMS with an
// explicit KMS Customer Master Key ID
String myKmsCmkId = ...;
GeneratePresignedUrlRequest genreq = new GeneratePresignedUrlRequest(
    myExistingBucket, myKey, HttpMethod.PUT)
    .withSSEAlgorithm(SSEAlgorithm.KMS.getAlgorithm())
    // Explicitly specifying your KMS customer master key id
    .withKmsCmkId(myKmsCmkId)
    ;
URL puturl = s3.generatePresignedUrl(genreq);
System.out.println("Presigned PUT URL using SSE-KMS with explicit CMK ID: "
    + puturl);

Here’s how to make use of the generated pre-signed PUT URL (from Example A) via the Apache HttpClient (4.3):


File fileToUpload = ...;
HttpPut putreq = new HttpPut(URI.create(puturl.toExternalForm()));
putreq.addHeader(new BasicHeader(Headers.SERVER_SIDE_ENCRYPTION,
    SSEAlgorithm.KMS.getAlgorithm()));
putreq.setEntity(new FileEntity(fileToUpload));
CloseableHttpClient httpclient = HttpClients.createDefault();
httpclient.execute(putreq);

Here’s how to make use of the generated pre-signed PUT URL from (Example B) via the Apache HttpClient (4.3):


File fileToUpload = ...;
HttpPut putreq = new HttpPut(URI.create(puturl.toExternalForm()));
putreq.addHeader(new BasicHeader(Headers.SERVER_SIDE_ENCRYPTION,
    SSEAlgorithm.KMS.getAlgorithm()));
putreq.addHeader(new BasicHeader(Headers.SERVER_SIDE_ENCRYPTION_AWS_KMS_KEYID,
    myKmsCmkId)); // Explicitly specifying your KMS customer master key id
putreq.setEntity(new FileEntity(fileToUpload));
CloseableHttpClient httpclient = HttpClients.createDefault();
httpclient.execute(putreq);

Here’s how to generate a pre-signed GET URL for use with SSE-KMS:


GeneratePresignedUrlRequest genreq = new GeneratePresignedUrlRequest(
    BUCKET, KEY, HttpMethod.GET);
// s3 configured to use SigV4
URL geturl = s3.generatePresignedUrl(genreq);
System.out.println("Presigned GET URL for SSE-KMS: " + geturl);

(Note in particular that generating a pre-signed GET URL for an S3 object encrypted using SSE-KMS is as simple as generating a regular pre-signed URL!)

Here’s how to make use of the generated pre-signed GET URL via the Apache HttpClient (4.3):


HttpGet getreq = new HttpGet(URI.create(geturl.toExternalForm()));
CloseableHttpClient httpclient = HttpClients.createDefault();
CloseableHttpResponse res = httpclient.execute(getreq);
InputStream is = res.getEntity().getContent();
String actual = IOUtils.toString(is);

In the next blog (Part 3), I will provide specific code examples that show how you can generate and consume pre-signed URLs using server side encryption with Amazon S3-managed keys (SSE-S3). 

Stay tuned!