S3 Presigner added to aws-sdk-java-v2

TL;DR

--S3 Presigner added to AWS SDK for Java 2.0 --Supports virtual-hosted style by default --Supports https by default --Changed the expiration date setting method --Use S3 Presigner to generate signed URLs

Introduction

This article is intended for backends using AWS on Java and Scala, as well as those engaged in SRE operations.

What is an S3 signed URL?

S3 has a mechanism to restrict access to an object by signing the URL it issues to download and upload it.

AWS SDK for Java 2.10.12 or earlier

Prior to AWS SDK for Java 2.10.12, AwsS3V4Signer was used to generate Presigned URLs. Below, the sample code is written in scala.

before.scala


import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider
import software.amazon.awssdk.auth.signer.AwsS3V4Signer
import software.amazon.awssdk.auth.signer.params.Aws4PresignerParams
import software.amazon.awssdk.http.{SdkHttpFullRequest, SdkHttpMethod}

val request = SdkHttpFullRequest
  .builder()
  .encodedPath("bucket/key")
  .host("s3.ap-northeast-1.amazonaws.com")
  .method(SdkHttpMethod.GET)
  .protocol("https")
  .build()

val params = Aws4PresignerParams
  .builder()
  .expirationTime(Instant.now().plusSeconds(300)
  .awsCredentials(DefaultCredentialsProvider.create().resolveCredentials())
  .signingName("s3")
  .signingRegion("ap-northeast-1")
  .build()

AwsS3V4Signer.create().presign(request, params).getUri

//Format of the generated signed URL
// https://s3.ap-northeast-1.amazonaws.com/bucket/key?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20200625T000000Z&X-Amz-SignedHeaders=host&X-Amz-Expires=300&X-Amz-Credential=XXX&X-Amz-Signature=YYY

AWS SDK for Java 2.10.12 or later

Starting with the AWS SDK for Java 2.10.12, S3 Presigner has been added [^ 1]. You can continue to use Aws S3V4Signer, but it is recommended to use S3 Presigner. The reason for this will be explained later, but on the other hand, AwsS3V4Signer is still used for the internal implementation of S3Presigner.

after.scala


import software.amazon.awssdk.regions.Region
import software.amazon.awssdk.services.s3.model.GetObjectRequest
import software.amazon.awssdk.services.s3.presigner.S3Presigner
import software.amazon.awssdk.services.s3.presigner.model.GetObjectPresignRequest

val presigner: S3Presigner = S3Presigner
    .builder()
    .region("ap-northeast-1")
    .build()

val request = GetObjectRequest
  .builder()
  .bucket("bucket")
  .key("key")
  .build()

val presignRequest = GetObjectPresignRequest
  .builder()
  .signatureDuration(Duration.ofSeconds(300))
  .getObjectRequest(request)
  .build()

presigner.presignGetObject(presignRequest).url.toURI

//Format of the generated signed URL
// https://bucket.s3.ap-northeast-1.amazonaws.com/key?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20200625T000000Z&X-Amz-SignedHeaders=host&X-Amz-Expires=300&X-Amz-Credential=XXX&X-Amz-Signature=YYY

What has changed?

  1. virtual-hosted style If you compare the generated URLs before and after, you can see that the bucket names are in different positions.
"https://s3.ap-northeast-1.amazonaws.com/bucket/key" //Before: path style
"https://bucket.s3.ap-northeast-1.amazonaws.com/key" //rear: virtual-hosted style

See below for the differences between the two.

  1. Request in path format
  2. Request for virtual hosting format
val request = SdkHttpFullRequest
  .builder()
  .encodedPath("key")
  .host("bucket.s3.ap-northeast-1.amazonaws.com")
  .method(SdkHttpMethod.GET)
  .protocol("https")
  .build()

In addition, AwsS3V4Signer can also generate a virtual-hosted style signed URL by setting SdkHttpFullRequest as above, but S3Presigner does not need to be aware of the implementation method.

2. How to specify the protocol

In AwsS3V4Signer, you can specify the protocol as shown in the .protocol ("https") part. However, S3Presigner does not have a method to specify the protocol. This is due to the fact that https is specified internally by default. It's hard to imagine the scene to use, but you can also select http by overwriting the endpoint as shown below.

val presigner: S3Presigner = S3Presigner
    .builder()
    .region("ap-northeast-1")
    .endpointOverride(new URI("http://s3.ap-northeast-1.amazonaws.com"))
    .build()

3. How to specify the expiration date

In AwsS3V4Signer, it was a way to specify a future date and time that you want to set as an expiration date. However, S3 Presigner uses a method of specifying the validity period as Duration.

//Before
val params = Aws4PresignerParams
  .builder()
  .expirationTime(Instant.now().plusSeconds(300)

//rear
val presignRequest = GetObjectPresignRequest
  .builder()
  .signatureDuration(Duration.ofSeconds(300))

Summary

[Amazon S3 path-style will be deprecated – and the story ahead –](https://aws.amazon.com/jp/blogs/news/amazon-s3-path-deprecation-plan-the-rest-of-the- story /)

AWS has announced that it will not support path style for buckets created after September 30, 2020. Therefore, it can be said that changes to S3 Presigner need to be dealt with early.

[^ 1]: For details on how to add it, click here [https://github.com/aws/aws-sdk-java-v2/issues/203)

Recommended Posts

S3 Presigner added to aws-sdk-java-v2
Save twitter icon to s3
[Note] Download from S3, upload to S3
upload images to refile heroku S3