Almost every web application at some point needs a way to upload or download files… and no one seems to enjoy building reliable and scalable upload/download servers… and for good reasons too! In fact, you’ll probably need to manage long-running connections and handle files that can be quite large (i.e videos). If you are running a fully serverless backend using API Gateway and Lambda, you probably know that you are limited in terms of payload size and execution time, so things get even more complicated there. In all these cases you should consider offloading this problem to S3 by using S3 pre-signed URLs. Pre-signed URLs are a fantastic tool to handle file download and upload directly in S3 in a managed and scalable fashion. But all that glitters is not gold and S3 pre-signed URLs come with quite a few gotchas… So in this talk, we will explore some use cases, see some potential implementations of S3 pre-signed URLs and uncover some of the gotchas that I discovered while using them. By the end of this talk, you should know exactly when to use pre-signed URLs and how to avoid most of the many mistakes I made with them!
11. Always re-imagining
We are a pioneering technology consultancy
focused on AWS and serverless
| |
Accelerated Serverless AI as a Service Platform Modernisation
loige
✉Reach out to us at
😇We are always looking for talent:
hello@fourTheorem.com
fth.link/careers
11
12. We host a weekly podcast about AWS
awsbites.com
loige 12
16. loige
Structure of an HTTP request
POST /profilepic/upload HTTP/1.1
Host: api.meower.com
Content-Type: text/plain
Content-Length: 9
Some data
Method
Path Version
Headers
Body
16
17. loige
What if it's a binary (like a picture)?
PUT /profilepic/upload HTTP/1.1
Host: api.meower.com
Content-Type: image/jpeg
Content-Length: 2097852
����JFIFHH������"��
���Dl��FW�'6N�()H�'p��FD3 [...]
read 2097852
bytes
17
41. loige
⚠VERY important details!
I lied to you a little in those diagrams... 🤥
It's a decent mental model, but it's not accurate 😅
The server never really talks with S3!
The server actually creates the signed URL by itself!
We will see later what's the security model around this idea!
41
42. loige
Is this a good solution? 🙄
✅It's a managed feature (a.k.a. no servers to manage)
✅We can upload and download arbitrarily big files with no practical limits*
✅Reasonably simple and secure
👍Seems good to me!
* objects in S3 are "limited" to 5TB (when using multi-part upload), 5 GB otherwise.
42
43. loige
Generating our first pre-signed URL
$ aws s3 presign
s3://finance-department-bucket/2022/tax-certificate.pdf
https://s3.amazonaws.com/finance-department-bucket/2022/tax-
certificate.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-
Credential=AKIA3SGQVQG7FGA6KKA6%2F20221104%2Fus-east-
1%2Fs3%2Faws4_request&X-Amz-Date=20221104T140227Z&X-Amz-
Expires=3600&X-Amz-SignedHeaders=host&X-Amz-
Signature=b228dbec8c1008c80c162e1210e4503dceead1e4d4751b4d9787
314fd6da4d55
Whoever has this URL can
download the tax certificate!
43
44. loige
What's in a pre-signed URL
https://s3.amazonaws.com/finance-department-bucket/2022/tax-
certificate.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-
Credential=AKIA3SGQVQG7FGA6KKA6%2F20221104%2Fus-east-
1%2Fs3%2Faws4_request&X-Amz-Date=20221104T140227Z&X-Amz-
Expires=3600&X-Amz-SignedHeaders=host&X-Amz-
Signature=b228dbec8c1008c80c162e1210e4503dceead1e4d4751b4d9787
314fd6da4d55
44
45. loige
What's in a pre-signed URL
https://s3.amazonaws.com
/finance-department-bucket
/2022/tax-certificate.pdf
?X-Amz-Algorithm=AWS4-HMAC-SHA256
&X-Amz-Credential=AKIA3SGQXQG7XXXYKKA6%2F20221104...
&X-Amz-Date=20221104T140227Z
&X-Amz-Expires=3600
&X-Amz-SignedHeaders=host
&X-Amz-Signature=b228dbec8c1008c80c162e1210e4503dceead1e4d4...
What if I change this to
/passwords.txt?
45
48. loige
🤓
Once a pre-signed URL is generated you
cannot edit it without breaking it
Photo by on
CHUTTERSNAP Unsplash
⚠Also note that you can use a pre-signed URL as many
times as you want until it expires
48
49. loige
🔐Permissions
Anyone with valid credentials can create a pre-signed URL (client side)
valid credentials = Role, User, or Security Token
The generated URL inherits the permissions of the credentials used to generate it
This means you can generate pre-signed URLs for things you don't have access to 😅
49
50. loige
$ aws s3 presign s3://ireland/i-love-you
https://ireland.s3.eu-west-1.amazonaws.com/i-love-you?X-Amz-
Algorithm=AWS4-HMAC-SHA256&X-Amz-
Credential=AKIA3ABCVQG7FGA6KKA6%2F20221115%2Feu-west-
1%2Fs3%2Faws4_request&X-Amz-Date=20221115T182036Z&X-Amz-
Expires=3600&X-Amz-SignedHeaders=host&X-Amz-
Signature=75749c92d94d03e411e7bbf64419f2af09301d1791b0df54c639
137c715f7888
😱
I swear I don't even know if this
bucket exists or who owns it!
50
56. loige
PUT Method
PUT <preSignedURL> HTTP/1.1
Host: <bucket>.s3.<region>.amazonaws.com
Content-Length: 2097852
����JFIFHH������"��
���Dl��FW�'6N�()H�'p��FD3 [...]
56
57. import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3'
import { getSignedUrl } from '@aws-sdk/s3-request-presigner'
const s3Client = new S3Client()
const command = new PutObjectCommand({
Bucket: "some-bucket",
Key: "some-object"
})
const preSignedUrl = await getSignedUrl(s3Client, command, {
expiresIn: 3600
})
console.log(preSignedUrl)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
loige
Only difference with the
previous example
57
58. loige
PUT Method - Limitations
You cannot set a limit on the upload size (max of 5 GB)! *
You can limit the Content-Type but you can specify exactly one
* Unless you know the exact size in advance
58
59. loige
POST method
It uses the multipart/form-data encoding (form upload)
Gives more freedom to the client to shape the request (Content-Type, file name, etc)
It uses a policy mechanism to define the "rules" of what can be uploaded
E.g. you can limit the supported mime types and provide a maximum file size
You can use it to upload from a web form and even configure the redirect URL
It's not really a URL but more of a pre-signed form!
59
61. loige
POST method Policy
A JSON object (Base64 encoded) that defines the upload rules (conditions) and the
expiration date
This is what gets signed: you cannot alter the policy without breaking the signature
{
"expiration": "2022-11-15T20:46:37Z",
"conditions": [
["content-length-range", 0, 5242880],
["starts-with", "$Content-Type", "image/"],
{"bucket": "somebucket"},
{"X-Amz-Algorithm": "AWS4-HMAC-SHA256"},
{"X-Amz-Credential": "AKIA3SGABCDXXXA6KKA6/20221115/eu-west-1/s3/aws4_request"},
{"X-Amz-Date": "20221115T194637Z"},
{"key": "picture.jpg"}
]
}
61
63. // you can use `url` and `fields` to generate an HTML form
const code = `<h1>Upload an image to S3</h1>
<form action="${url}" method="post" enctype="multipart/form-data">
${Object.entries(fields).map(([key, value]) => {
return `<input type="hidden" name="${key}" value="${value.replace(/"/g, '"')}">`
}).join('n')}
<div><input type="file" name="file" accept="image/png"></div>
<div><input type="submit" value="Upload"></div>
</form>`
1
2
3
4
5
6
7
8
9
10
loige 63
64. loige
Limitations and quirks
It supports only 1 file (cannot upload multiple files in one go)
The file field must be the last entry in the form
(S3 will ignore every other field after the file)
From the browser (AJAX) you need to enable CORS on the bucket
64
65. loige
Should I use PUT or POST? 🧐
PUT is simpler but definitely more limited
POST is slightly more complicated (and less adopted) but it's more flexible
You should probably put some time into learning POST and use that!
65
66. loige
Pre-signed URLs for other operations
S3 pre-signed URLs are not limited to GET, PUT or POST operations
You can literally create pre-signed URLs for any command
(DeleteObject, ListBuckets, MultiPartUpload, etc...)
66
67. loige
Do you need moar examples? 😼
github.com/lmammino/s3-presigned-urls-examples
67
68. loige
... In summary
S3 pre-signed URLs are a great way to authorise operations on S3
They are generally used to implement upload/download features
The signature is created client-side so you can sign anything. Access is validated at
request time
This is not the only solution, you can also use the JavaScript SDK from the frontend
and get limited credentials from Cognito (Amplify makes that process simpler)
For upload you can use PUT and POST, but POST is much more flexible
💬PS: Meower.com doesn't really exist... but... do you want to invest?! It's a great
idea, trust me!
68
69. Cover photo by on
Kelly Sikkema Unsplash
fourtheorem.com
THANKS! 🙌
fth.link/presign
loige
It's a wrap!
69