Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get non-expiring permanent amazon s3 object url

My code looks like this:

module Operations
  class UploadFileToS3 < MethodStruct.new(:params)
    def call
      s3 = Aws::S3::Resource.new(region: ENV['S3_REGION'])
      obj = s3.bucket(ENV['S3_BUCKET_NAME']).object(object_name)
      obj.upload_file(params[:tempfile_path],
                      content_type: params[:content_type],
                      acl: 'public-read')
      {
        url: obj.presigned_url(:get),
        # url: obj.public_url,
        filename: object_name
      }
    end

    private

    def object_name
      "#{params[:timestamp]}-#{params[:uuid]}#{params[:thumbname_suffix]}"
    end
  end
end

For all uploaded files, the following properties are set automatically:

Expiry Date: None
Expiration Rule: N/A

Uploaded objects's Permissions include:

Everyone: Open/Download

Bucket's Permissions include:

Everyone: View Permissions

Bucket policy looks like this:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AddPerm",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::<BUCKETNAME>/*"
        }
    ]
}    

Commented out obj.public_url returns bare link to object (no query string attached), which expires as well and then renders xml file. Bare link taken straight from the object props expires too, even if I manually add to the object's Permissions:

Everyone: View Permissions

Even if I make an object public via AWS console, the link it gives me includes header X-Amz-Expires=300.

Trying to use obj.presigned_url(:get, acl: 'public-read') throws ArgumentError - unexpected value at params[:acl].

I would like to use this bucket as storage for avatars so everyone should be able to see the linked picture at all times. Any ideas how to get the really permanent url that will not expire nor today neither in one year?

like image 362
medik Avatar asked Mar 14 '23 17:03

medik


2 Answers

If the ACL of the object is public-read then the non-expiring URL for the object is simply this:

http[s]://bucket-name.s3.amazonaws.com/path/to/file.ext

bare link to object (no query string attached), which expires as well and then renders xml file

No, it doesn't. You have made an error in your observations, or you are looking at a cached response. A URL with no query string has no possible mechanism that would cause it to expire. Note the RequestId and HostId in the xml. If they are not changing, you are dealing with a cached response, because they always change from response to response from S3.

like image 90
Michael - sqlbot Avatar answered Mar 25 '23 10:03

Michael - sqlbot


You need to specify acl like public_read could be a symbol or string

  obj.upload_file(params[:tempfile_path],
                  content_type: params[:content_type],
                  acl: :public_read)
  {
    url: obj.public_url,
    filename: object_name
  }

Updated code

obj = s3.bucket(ENV['S3_BUCKET_NAME']).object(object_name)
obj.write(:file => image_location)
obj.acl = :public_read
obj.public_url.to_s

Otherwise private permission is being set.

like image 24
Zahid Avatar answered Mar 25 '23 09:03

Zahid