113

Is there any way that I can generate Pre-Signed URL's without any expiry date ? I'm developing a Email app where my attachments will be saved in S3. Also please let me know what is the best way to download attachments via JavaScript SDK.

I'm using below code

var params = {Bucket: 'bucket', Key: 'key', Expires: 60};
var url = s3.getSignedUrl('getObject', params);
console.log('The URL is', url);
Jonik
  • 80,077
  • 70
  • 264
  • 372
srinisunka
  • 1,159
  • 2
  • 7
  • 10
  • Answer is, you can't! It clearly defeats the purpose of having a signed URL which you can expire after a given amount of time & enforce access control. If you don't wanna expire your URL, you can very well use public objects. – Prasanna Sundar Feb 06 '20 at 06:01
  • 1
    We can try some hack here , save image name and s3 bucket name into database instead of presigned url and while display create the "presigned" URLs with max expire time and send to browser. – vaquar khan May 21 '20 at 06:09

5 Answers5

126

The maximum expiration time for presigned url is one week from time of creation. So there is no way to have a presigned url without expiry time.

Skydan
  • 1,196
  • 1
  • 12
  • 24
yottabytt
  • 2,280
  • 1
  • 18
  • 14
  • 5
    Do you have a link to the documentation that states that? I couldn't find it anywhere. That would be very helpful. Thanks. – Volkan Paksoy Oct 08 '15 at 09:43
  • 3
    I did not see that in any documentation. I found in a comment in the source code of the presign_v4 file which comes with aws sdk. In my case it is ruby sdk by installing ruby aws sdk gem v 1.58. The exact location would be Home/Library/Ruby/Gems/2.0.0/gems/aws-sdk-v1-1.58.0/lib/aws/s3/presign_v4.rb – yottabytt Oct 09 '15 at 07:39
  • 35
    Cool, thanks. I found it later [here](http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html): *"The minimum value you can set is 1, and the maximum is 604800 (seven days)."* – Volkan Paksoy Oct 09 '15 at 07:56
  • 2
    The 7 day limit applies when you use signature v4. – jarmod Sep 05 '19 at 16:34
  • 4
    Maximum expiration depends on the some other things. Good explanation here: https://aws.amazon.com/premiumsupport/knowledge-center/presigned-url-s3-bucket-expiration/ – ejlp12 Jun 19 '20 at 01:44
  • @ejlp12 - that links is very useful but it leaves the question open of whether there is another type of authorization token that won't expire after 7 days, and the answer to that is apparently - no. – Guss Jul 15 '21 at 08:33
39

It depends on how you generate the S3 pre-signed URL. Specifically, which signature version you use and what type of IAM credentials you use.

The credentials that you can use to create a pre-signed URL include:

  • IAM instance profile (temporary, rotated credentials): valid up to 6 hours
  • STS (temporary credentials): valid up to 36 hours
  • IAM user (long-term credentials): valid up to 7 days when using signature v4
  • IAM user (long-term credentials): valid till the end of the epoch when using signature v2

Note specifically:

  • signature v2 is potentially deprecated
  • the expiration limit for signature v2 is different to signature v4
  • signature v4 offers some security and efficiency benefits over v2
  • if you use STS credentials to generate a pre-signed URL then the URL will expire when the STS credentials expire, if that is earlier than the explicit expiration that you requested for the pre-signed URL
  • creating pre-signed URLs that are valid till the end of the epoch is not the best security practice

For more, see:

jarmod
  • 71,565
  • 16
  • 115
  • 122
18

A somewhat solution for you might be to make the AWS CloudFront distribution that serves your S3 bucket with limited access to only Distribution Origin Access Identity and then using CloudFront Signed urls. Which expiry time can be even in years. So for unlimited or semi-unlimited urls I would recommend such solution.

Ravbaker
  • 1,780
  • 1
  • 13
  • 11
  • can you post the code/link for the aws cloudfront signed urls? – VishalParkash Jul 15 '20 at 10:19
  • @VishalParkash Here is official documentation from AWS website with code examples how to make those links. https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/PrivateCFSignatureCodeAndExamples.html – Ravbaker Jul 23 '20 at 12:37
1

Not sure if you want to save the attachments indefinitely. Nonetheless, one option could be that you use an API Gateway. You will need to handle authentication and authorization yourself. You could use a token for instance that you can compare with a token in your database. The token grants access to one certain file and is part of the request URL (or it's request headers). But first on how to generate the "pre-signed URL":

  1. when an attachment is uploaded to S3 you generate a token, i.e. JWT token, with the file name.
  2. Save the token in a DynamoDB, possibly with an expiry date, if needed
  3. Return the API Gateway URL and the generated token to the user, e.g. https://get-your-attachment.io/download?token=123
  4. If the token expires use DynamoDB streams to find the file in S3 and remove it from S3 to have it cleaned up

If a user wants to download a file, they open the URL provided in step 3. The API Gateway calls an authorization Lambda. This Lambda checks that the token is still in the DynamoDB. If so, the request triggers another Lambda function which will extract the file name out of the token and return the file. You have to return the file encoded, set the response headers properly and take care of the service limits.

If the download can only be done from within your app and the link cannot be shared nor used outside of the app, then you could skip returning the file through the API Gateway. Authorization will stay as described above. But instead of returning the file, the Lambda function returns a pre-signed URL, valid for maybe 10 minutes. Your app uses the URL for another request and receives the file from S3.

As for the second part of your question on how to download the files as simple fetch(preSignedS3URL) will be enough.

st.huber
  • 1,481
  • 2
  • 24
  • 45
-10

On client you could do:

const image = image.split('&Expires')[0]

That's one of the workarounds that i used

  • 1
    This will not work. The OP is asking for a way to generate a link that has no expiry date (in otherwords, that can't expire). Removing the `Expires=` will only make the URL invalid and unusable. You're misunderstanding the question. –  Nov 03 '21 at 14:44