How to Create Presigned URLs in Spring Cloud AWS for S3 Storage

Imran Shaikh
0

Amazon S3 buckets are initially private, meaning they cannot be accessed publicly. To temporarily grant others access to specific objects, you can create S3 presigned URLs.


These URLs provide limited, time-bound access to the object, allowing you to share the content securely for a specific period


Presigned URLs can be created for both downloads (using the GET HTTP method) and uploads (using the PUT HTTP method).


This allows you to securely share files for downloading or accepting uploads from others within a specified timeframe


In this tutorial, we'll demonstrate how to grant temporary access to S3 bucket objects using Spring Cloud AWS S3 within a Spring Boot application.

The complete code for this project is available on my GitHub repository (getButton) #text=(GitHub) #icon=(share) #color=(#000000)

How to Create Presigned URLs in Spring Cloud AWS for S3 Storage
toc

Dependencies


To get started with this tutorial, you'll need to add the following dependencies to your Spring Boot project's. This dependency provides the necessary components for interacting with AWS services, including S3.


Gradle

ext {
    springCloudAwsVersion = '3.0.0'
}

dependencies {
    // spring cloud aws BOM(Bill of materials)
    implementation platform("io.awspring.cloud:spring-cloud-aws-dependencies:${springCloudAwsVersion}")
    implementation 'io.awspring.cloud:spring-cloud-aws-starter-s3'
    // AWS launched a high level file transfer utility, called Transfer Manager and a CRT based S3 client.
    // The starter automatically configures and registers a software.amazon.awssdk.transfer.s3.S3TransferManager bean if the following dependency is added to the project:
    implementation 'software.amazon.awssdk:s3-transfer-manager'
    //Transfer Manager works the best with CRT S3 Client. To auto-configure CRT based S3AsyncClient add following dependency to your project:
    implementation 'software.amazon.awssdk.crt:aws-crt'
}

Maven

<dependencies>
    <dependency>
        <groupId>io.awspring.cloud</groupId>
        <artifactId>spring-cloud-aws-starter-s3</artifactId>
    </dependency>
	
    <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>s3-transfer-manager</artifactId>
    </dependency>
	
    <dependency>
        <groupId>software.amazon.awssdk.crt</groupId>
        <artifactId>aws-crt</artifactId>
    </dependency>
</dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>io.awspring.cloud</groupId>
            <artifactId>spring-cloud-aws-dependencies</artifactId>
            <version>{project-version}</version>
            <type>pom</type>
            <scope>import</scope>
       </dependency>
    </dependencies>
</dependencyManagement>

Configuration and Credentials


Before diving into bucket operations, let's configure our Spring Boot application to interact with AWS S3. Spring Cloud AWS offers auto-configuration for S3Client, S3TransferManager, and S3Template, making setup a breeze.


Here's what you need to add to your application.properties file:


 # s3 Configuration
 spring.cloud.aws.credentials.access-key=
 spring.cloud.aws.credentials.secret-key=
 # Configures endpoint used by S3Client, I'm woorking in the Asia Pacific (Mumbai) hence, I've configure ap-south1 region and endpoint
 spring.cloud.aws.s3.endpoint=https://s3.ap-south-1.amazonaws.com
 spring.cloud.aws.region.static=ap-south-1

IAM Permissions for Creating Presigned URLs


To follow this tutorial, your IAM user must have the s3:GetObject and s3:PutObject permissions.


You might be wondering why these permissions are necessary if presigned URLs are used to grant access to non-S3 bucket owners. The answer is that presigned URLs can only be generated by someone who already has access to the underlying object.


 {
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "DownloadObject",
            "Effect": "Allow",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::*/*"
        },
        {
            "Sid": "UploadObject",
            "Effect": "Allow",
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::*/*"
        }
    ]
 }

Creating Presigned URLs for GET Requests with S3Presigner


Let's create our first presigned URL for a GET request using the S3Presigner. Before we begin, ensure you have an active S3 bucket and an object within it.


In this example, I'll use a bucket named "learnjavaskills" with an index.html file. We'll generate a URL to download this file.


 import io.awspring.cloud.s3.S3Exception;
 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;
 import software.amazon.awssdk.services.s3.presigner.model.PresignedGetObjectRequest;

 public URL createPreSignedUrlUsingS3PresignerForGetRequest(String bucketName, String key) {
    try {
        GetObjectRequest objectRequest = GetObjectRequest.builder()
                .bucket(bucketName)
                .key(key)
                .build();

        GetObjectPresignRequest objectPresignRequest = GetObjectPresignRequest.builder()
                .signatureDuration(Duration.ofMinutes(10)) // URL will expire after 10 minutes
                .getObjectRequest(objectRequest)
                .build();
        PresignedGetObjectRequest presignedGetObjectRequest = s3Presigner.presignGetObject(objectPresignRequest);

        URL url = presignedGetObjectRequest.url();
        System.out.println("presigned url : " + url.toString());
        return url;
    } catch (S3Exception s3Exception) {
        s3Exception.printStackTrace();
        return null;
    }
 }

S3Presigner : is an interface that allows you to sign an S3 SdkRequest, enabling it to be executed without requiring additional authentication from the caller.


GetObjectRequest : Retrieves objects from Amazon S3. To use the GET method, you must have READ access to the object. If you grant READ access to the anonymous user, you can retrieve the object without requiring an authorization header.


GetObjectPresignedRequest : A request to create a presigned URL for a GetObjectRequest, allowing it to be executed at a later time without requiring additional signing or authentication.


Downloading Files Using Presigned URLs with Postman

Once you have the presigned URL, let's use Postman to download the object from the S3 bucket. As you'll see in the response, you can successfully read the index.html file without providing any credentials.


downloading file using presigned url

Presigned URL Expiration Responses

The presigned URL we created has a validity of only 10 minutes. If a user attempts to download the file after this interval, Amazon S3 will deny access


presigned url expired

Creating Presigned URLs for GET Requests with S3Template


S3Template is a high-level API provided by Spring Cloud AWS that simplifies interactions with Amazon S3. It offers a convenient way to perform common operations like creating, deleting, and managing buckets and objects.


S3Template significantly simplifies the process of creating presigned URLs. By calling the createSignedGetUrl method, you can easily generate a presigned URL for a specified bucket, object key, and duration, allowing you to securely share access to your S3 objects


 import io.awspring.cloud.s3.S3Exception;
 import io.awspring.cloud.s3.S3Template;

 public URL createPreSignedUrlUsingS3TemplateForGetRequest(String bucketName, String key) {
    try {
        return s3Template.createSignedGetURL(bucketName, key, Duration.ofMinutes(10));
    } catch (S3Exception s3Exception) {
        s3Exception.printStackTrace();
        return null;
    }
 }

Downloading Files Using Presigned URLs with Postman

I've created a presigned URL for an image. Let's verify its functionality by downloading the image.


downloading file using presigned url

Creating Presigned URLs for PUT Requests with S3Presigner


Similarly, we can create a presigned URL for uploading objects to Amazon S3. In this case, we'll need to use a PUT request.


Let's explore how to create a presigned URL for a PUT request using S3Presigner.


To create a presigned URL for uploading a file, we can use the presignPutObject method of the S3Presigner interface.


 import io.awspring.cloud.s3.S3Exception;
 import software.amazon.awssdk.services.s3.model.PutObjectRequest;
 import software.amazon.awssdk.services.s3.presigner.S3Presigner;
 import software.amazon.awssdk.services.s3.presigner.model.PresignedPutObjectRequest;
 import software.amazon.awssdk.services.s3.presigner.model.PutObjectPresignRequest;

 public URL createPreSignedUrlUsingS3PresignerForPutRequest(String bucketName, String key) {
    try {
        PutObjectRequest putObjectRequest = PutObjectRequest.builder()
                .bucket(bucketName)
                .key(key)
                .build();
        PutObjectPresignRequest putObjectPresignRequest = PutObjectPresignRequest.builder()
                .signatureDuration(Duration.ofMinutes(10)) // URL will expire after 10 minutes
                .putObjectRequest(putObjectRequest)
                .build();

        PresignedPutObjectRequest presignedPutObjectRequest = s3Presigner.presignPutObject(putObjectPresignRequest);
        URL url = presignedPutObjectRequest.url();
        System.out.println("presigned url : " + url.toString());
        return  url;
    } catch (S3Exception s3Exception) {
        s3Exception.printStackTrace();
        return null;
    }
 }

PutObjectRequest : Uploads a new object to the specified Amazon S3 bucket. It can also optionally upload object metadata and set a canned access control policy for the new object.


PutObjectPresignRequest : A request to pre-sign a PutObjectRequest so that it can be executed at a later time without requiring additional signing or authentication.


Uploading Files Using Presigned URLs with Postman

Let's verify if the upload presigned URL works by using Postman. Ensure that you set the HTTP method to PUT.


Uploading Files Using Presigned URLs with Postman

Creating Presigned URLs for PUT Requests with S3Template


Spring Cloud AWS simplifies the process of creating presigned URLs for PUT requests.


By using the createSignedPutUrl method of S3Template, you can easily generate a presigned URL for uploading objects to your S3 bucket, specifying the bucket name, object key, and desired duration of validity.


 import io.awspring.cloud.s3.S3Exception;
 import io.awspring.cloud.s3.S3Template;

 public URL createPreSignedUrlUsingS3TemplateForPutRequest(String bucketName, String key) {
	try {
            return s3Template.createSignedPutURL(bucketName, key, Duration.ofMinutes(10));
	} catch (S3Exception s3Exception) {
		s3Exception.printStackTrace();
            return null;
	}
 }

Conclussion


In this blog tutorial, we've explored the concept of presigned URLs and their significance in securely sharing access to S3 objects. We've learned how to create presigned URLs for both GET (download) and PUT (upload) requests using both S3Presigner and S3Template.


By leveraging presigned URLs, you can grant temporary access to specific S3 objects, enabling you to share files or data securely with external parties without compromising your account's security.


This is particularly useful in scenarios where you need to provide controlled access to sensitive information or collaborate with external teams.


Remember to carefully manage the duration of your presigned URLs to ensure that access is limited to the necessary timeframe.


By following the guidelines and examples provided in this tutorial, you can effectively utilize presigned URLs to enhance the security and flexibility of your S3-based applications.

The complete code for this project is available on my GitHub repository (getButton) #text=(GitHub) #icon=(share) #color=(#000000)

Keep learning and keep growing.

Post a Comment

0 Comments
Post a Comment (0)

#buttons=(Accept !) #days=(20)

Our website uses cookies to enhance your experience. Learn More
Accept !
To Top