Making sure that your images and files are all secure is very important, but sometimes you also want to share them. In this article we’re going to learn how to secure out the bucket before adding signed URLs to allow temporary access to our files by people we trust.
If you want to follow along then you can. You can clone this branch and continue from there:
git clone –single-branch –branch l35-signed-urls git@github.com:SamWSoftware/ServerlessYoutubeSeries.git
Securing the S3 Bucket and Images
In our serverless.yml
file we need to remove the AccessControl: PublicRead
field on the bucket config. This will restrict the ability to see the files within the bucket.
Next we need to make sure the images that we’re uploading are not public either. If we go to them lambdas/endpoints/imageUpload.js
and find the s3 file upload then we can update that functionality. We need to start by adding the import of the top of the file.
import S3 from '../common/S3';
We then need to update the s3 write functionality, making sure to set the ACL to null.
await S3.write(buffer, key, process.env.imageUploadBucket, null, body.mime);
If we save all of this and deploy this then when we upload an image we get a access denied
response when we try and access the newly uploaded images.
Adding Signed URLs
With our files secured we need to find a way to give temporary access to people that we need to.
In our common/s3.js
file we can add a new method to the object. This is going to be our way of requesting a secure signed URL.
async getSignedURL(bucket, fileName, expriySeconds) {
return s3Client.getSignedUrl('getObject', {
Bucket: bucket,
Key: fileName,
Expires: expriySeconds,
});
},
This function takes three parameters, the bucket, file name, and expiry in seconds. This expiry is how long the signed URL will be valid for.
Back in the imageUpload.js
the endpoint we can change the URL constant that used to be a template string.
const url = await S3.getSignedURL(process.env.imageUploadBucket, key, 60);
In this case, we are passing in expiry of 60 seconds and we’ll test that out later. For now, we can deploy the new function code. As we’re just updating an existing lambda we can use sls deploy -f imageUpload
.
Testing
If we go back into our test image upload app, we can upload an image again. We can see that the image is uploaded as we expect and is shown on screen. If we inspect the image we can copy the image URL and paste it into a new tab. You may have noticed that it’s a lot longer than the old public URLs. This is because it has an access key and secret in the query string parameters. This is how it allows only certain people to access the file.
If you do this within 60s the new tab will contain just the image. If you wait for a short while then refresh the page you might get access denied. If you still see the image then wait for another 20s and refresh the page again.
This access denied
the response shows that the expiry is up and that URL is not valid anymore. If you want to give permanent access to that file to someone you could have set the expirySeconds to null.