2022-10-05

Presigned URL in Amazon S3

What is Presigned URL

Presigned URLs are a unique feature offered by Amazon S3 that allows temporary, secure access to private objects in your S3 buckets. These URLs carry the necessary authentication information within themselves and are generated using the AWS security credentials of the S3 bucket's owner.

In essence, a presigned URL is a URL for an object in Amazon S3 that is appended with additional parameters for security credentials and an expiration time. Once this URL is generated, anyone who receives it can use it to access the object. This holds true even if the object is otherwise private and inaccessible to the user.

Presigned URL
AWS S3 Presigned URL Upload Tutorial in Python

Why Use Presigned URL

Presigned URLs provide an efficient solution for various use-cases. One of the key reasons to use them is when you need to provide temporary access to a private object. This can be handy, for example, when you need to share a file with someone, but you don't want to change the object's permissions or manage complex access control lists.

Another common use-case is when you want to let users upload or download files to/from your S3 bucket without requiring them to have an AWS account or directly access your AWS credentials. For instance, you can generate a presigned URL for an upload operation and provide this to a user. The user can then upload a file directly to your S3 bucket using this URL, and all of this can happen without them ever needing to know your AWS access keys.

Presigned URLs also serve a crucial role in web development. They allow the direct serving of download links from a website or a web application. This can be achieved without the need for server-side code to fetch the file, which can save bandwidth and improve performance.

Working with Presigned URLs in Amazon S3

The process of generating a presigned URL varies depending on the language and AWS SDK you're using. In this chapter, I'll illustrate the process using the AWS SDK for Python, known as Boto3.

For a download operation, the following Python code generates a presigned URL:

python
import boto3
from botocore.exceptions import NoCredentialsError

def create_presigned_url(bucket_name, object_name, expiration=3600):
    """Generate a presigned URL to share an S3 object

    :param bucket_name: string
    :param object_name: string
    :param expiration: Time in seconds for the presigned URL to remain valid
    :return: Presigned URL as string. If error, returns None.
    """

    # Generate a presigned URL for the S3 object
    s3_client = boto3.client('s3')
    try:
        response = s3_client.generate_presigned_url('get_object',
                                                    Params={'Bucket': bucket_name,
                                                            'Key': object_name},
                                                    ExpiresIn=expiration)
    except NoCredentialsError:
        return None

    # The response contains the presigned URL
    return response

For an upload operation, you can generate a presigned URL as follows:

python
def create_presigned_post(bucket_name, object_name, fields=None, conditions=None, expiration=3600):
    """Generate a presigned URL S3 POST request to upload a file

    :param bucket_name: string
    :param object_name: string
    :param fields: Dictionary of prefilled form fields
    :param conditions: List of conditions to include in the policy
    :param expiration: Time in seconds for the presigned URL to remain valid
    :return: Dictionary with the following keys:
        url: URL to post to
        fields: Dictionary of form fields and values to submit with the post
    """

    # Generate a presigned S3 POST URL
    s3_client = boto3.client('s3')
    try:
        response = s3_client.generate_presigned_post(bucket_name,
                                                     object_name,
                                                     Fields=fields,
                                                     Conditions=conditions,
                                                     ExpiresIn=expiration)
    except NoCredentialsError:
        return None

    # The response contains the presigned URL and required fields
    return response

After running this code with the appropriate bucket name and object name, you'll receive a response that looks like this:

{
  "url": "https://mybucket.s3.amazonaws.com/",
  "fields": {
    "key": "myobjectkey",
    "AWSAccessKeyId": "AKIAIOSFODNN7EXAMPLE",
    "policy": "eyJleHBpcmF0aW9uIjogIjIwMjAtMDktMjlUMTk6MzA6MjBaIiwgImNv...",
    "signature": "b5cc6dc8dd2700d2a35f4e6a39c6b2b44b0215f5ecee0630..."
  }
}

This response includes the URL to which the client should POST and the fields the client must include in the form-data of the POST request.

References

https://aws.amazon.com/blogs/storage/using-presigned-urls-to-identify-per-requester-usage-of-amazon-s3/
https://medium.com/@aidan.hallett/securing-aws-s3-uploads-using-presigned-urls-aa821c13ae8d
https://beabetterdev.com/2021/09/30/aws-s3-presigned-url-upload-tutorial-in-python/?noamp=mobile

Ryusei Kakujo

researchgatelinkedingithub

Focusing on data science for mobility

Bench Press 100kg!