Skip to content

Instantly share code, notes, and snippets.

@plindberg
Created August 5, 2017 16:46
Show Gist options
  • Save plindberg/bdd3bfc198d0c2db9474710a69ad1066 to your computer and use it in GitHub Desktop.
Save plindberg/bdd3bfc198d0c2db9474710a69ad1066 to your computer and use it in GitHub Desktop.
How to set up an AWS Lambda function for returning S3 pre-signed URLs for uploading files.

README

Granted, this is little more than an obfuscated way of having a publicly writable S3 bucket, but if you don’t have a server which can pre-sign URLs for you, this might be an acceptable solution.

For this to work, you take the following steps:

  1. Create a Lambda func, along with a new IAM role, keeping the default code.
  2. Create an API in the API Gateway.
  3. Create a resource in said API.
  4. Create a POST method for that API resource, pointing it to the above Lambda func.
  5. Deploy the API to a new stage.
  6. Verify that you can call the Lambda func using curl followed by the URL shown for the stage, resource, and method.
  7. Create an S3 bucket if you haven’t already, and one or more folders you want to upload to.
  8. Add a bucket policy granting public read access to those folders (a sample is included in this gist).
  9. Create an IAM policy granting write permissions in those folders (also included).
  10. Attach this policy to the IAM role created above.
  11. Update the Lambda func with the code in this gist.
  12. Add a configuration variable named s3_bucket with the name of your S3 bucket.
  13. Verify that you can call it using curl followed by the same URL as previously, followed by the parameters --request POST --header 'Content-Type: application/json --data '{"object_key": "folder/filename.ext"}'
  14. Finally, verify that you can upload a file to the URL returned, using curl --upload-file followed by the path to some file and the URL received in the previous step.

That’s it!

'use strict';
const AWS = require('aws-sdk');
const s3 = new AWS.S3({signatureVersion: 'v4'});
exports.handler = (event, context, callback) => {
const bucket = process.env['s3_bucket'];
if (!bucket) {
callback(new Error(`S3 bucket not set`));
}
const key = event['object_key'];
if (!key) {
callback(new Error('S3 object key missing'));
return;
}
const params = {'Bucket': bucket, 'Key': key};
s3.getSignedUrl('putObject', params, (error, url) => {
if (error) {
callback(error);
} else {
callback(null, {url: url});
}
});
};
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"s3:PutObject"
],
"Effect": "Allow",
"Resource": [
"arn:aws:s3:::mybucket/folder1/*"
]
},
{
"Action": [
"s3:PutObject"
],
"Effect": "Allow",
"Resource": [
"arn:aws:s3:::mybucket/folder2/*"
]
}
]
}
{
"Version": "2008-10-17",
"Statement": [
{
"Sid": "AllowPublicRead",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::mybucket/folder1/*"
},
{
"Sid": "AllowPublicRead",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::mybucket/folder2/*"
}
]
}
@karges612
Copy link

its my bad , there is a space between content type and json . but even after clearing it , this is the error am getting "object key missing"
below is the command.
curl https://94drtx3a0a.execute-api.us-west-1.amazonaws.com/uploadtest --request POST --header 'Content-Type:application/json' {"object_key": "C:\poclog.txt"}'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment