AWS S3 uploads using pre-signed URLs

How can I allow users to access objects in S3?

So what are presigned URLs anyway?

  1. Bucket: The bucket that the object is in (or will be in)
  2. Key: The name of the object
  3. Expires: The amount of time that the URL is valid
  1. X-AMZ-Algorithm
  2. X-AMZ-Credential
  3. X-AMZ-Date
  4. X-AMZ-Expires
  5. X-AMZ-Signature
  6. X-AMZ-SignedHeaders
https://presignedurldemo.s3.eu-west-2.amazonaws.com/image.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAJJWZ7B6WCRGMKFGQ%2F20180210%2Feu-west-2%2Fs3%2Faws4_request&X-Amz-Date=20180210T171315Z&X-Amz-Expires=1800&X-Amz-Signature=12b74b0788aa036bc7c3d03b3f20c61f1f91cc9ad8873e3314255dc479a25351&X-Amz-SignedHeaders=host

How do I create a presigned URL then?

  1. Navigate to S3 and create a bucket. The bucket name must be unique.
  2. Navigate to IAM.
  3. Create a User with Programmatic access.
  4. Click Next: Permissions.
  5. Click the Attach existing policies directly box and Create policy.
  6. Use the visual editor to select the S3 Service. We only need a couple of access requirements; so expand out the access level groups.
  7. Ensure that GetObject under the READ section and PutObject under the write section are both ticked.
  8. Set the resources you want to grant access to; specify the bucket name you created earlier and click Any for the object name.
  9. We’re not specifying any Request conditions.
  10. Click Review Policy and enter a name for the policy. Save the policy.

Generating the presigned URLs using the AWS JS SDK

require('dotenv').load();require('dotenv').config();var AWS = require('aws-sdk');var credentials = {accessKeyId: process.env.S3_ACCESS_KEY,secretAccessKey : process.env.S3_SECRET_KEY};AWS.config.update({credentials: credentials, region: 'eu-west-2'});var s3 = new AWS.S3();var presignedGETURL = s3.getSignedUrl('getObject', {Bucket: 'presignedurldemo',Key: 'image.jpg', //filenameExpires: 100 //time to expire in seconds});
var presignedPUTURL = s3.getSignedUrl('putObject', {Bucket: 'presignedurldemo',Key: 'user12/image.jpg', //filenameExpires: 100 //time to expire in seconds});

Using the presigned URLs

A successfully uploaded image file

So are there any drawbacks?

Presigned POST URLs

POST URL Parameters

  1. Bucket: process.env.S3_BUCKET (The bucket name)
  2. Expires: 1800 (Time to expire in seconds (30m))
  3. key: ‘image.jpg’ (Filename)
  4. { acl: ‘private’ } (It defines which AWS accounts or groups are granted access and the type of access.)
  5. { success_action_status: “201” } (HTTP status code returned if successful)
  6. [‘starts-with’, ‘$key’, ‘’] (The value must start with the specified value (e.g. ‘user1/’. In our case image has no additional prefix ‘’)
  7. [‘content-length-range’, 0, 100000] (Specify the range of the content you are uploading in Bytes)
  8. {‘x-amz-algorithm’: ‘AWS4-HMAC-SHA256’} (Specify the signing algorithm used during signature calculation)

How can I secure this further?

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>PUT</AllowedMethod>
<AllowedMethod>POST</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<AllowedHeader>Authorization</AllowedHeader>
</CORSRule>
</CORSConfiguration>
S3_ACCESS_KEY=anaccesskeyishere
S3_SECRET_KEY=asecretkeyishere
S3_BUCKET=presignedurldemo
S3_REGION=eu-west-2

References

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store