Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Upload files to S3 via Cloudfront

I'm trying to upload files to S3 via Cloudfront. I've created a bucket with name my-files. Bucket CORS settings:

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <AllowedMethod>PUT</AllowedMethod>
        <AllowedMethod>POST</AllowedMethod>
        <AllowedMethod>DELETE</AllowedMethod>
        <AllowedMethod>HEAD</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>Authorization</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

I've created Cloudfront distribution. Here is configuration which can be important:

General:

Delivery Method: Web
Alternate Domain Names (CNAMEs) files.example.com

Origins:

Origin Domain Name: my-files.s3.amazonaws.com
Restrict Bucket Access: Yes
Grant Read Permissions on Bucket: Yes, Update Bucket Policy

Behaviour:

Path Pattern: Default (*)
Origin: S3-my-files
Viewer Protocol Policy: HTTP and HTTPS
Allowed HTTP Methods: GET, HEAD, OPTIONS, PUT, POST, PATCH, DELETE
Whitelist Headers: Access-Control-Request-Headers, Access-Control-Request-Method, Origin
Object Caching: Use Origin Cache Headers
Restrict Viewer Access (Use Signed URLs or Signed Cookies): Yes
Trusted Signers: Self

I can create signed URL for file download and it works correctly. I can create CNAME for S3 bucket, upload a file to S3 using pre-signed URL and this also works correctly. When I'm trying to upload file via Cloudfront then I'm getting a 403 response (OPTIONS):

XMLHttpRequest cannot load http://files.example.com/. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://0.0.0.0:5000' is therefore not allowed access. The response had HTTP status code 403.

Is it possible to use Cloudfront with signed URLs for uploading files? How can I set allowed origins to allow file uploads from localhost?

like image 299
eshlox Avatar asked Oct 21 '16 19:10

eshlox


People also ask

Can CloudFront be used for uploads?

Aws recommend to use CloudFront for upload/download file < 1Gb in size. For larger files, the S3 Transfer Accelerator is recommended.

How do I upload files to AWS S3?

In the Amazon S3 console, choose the bucket where you want to upload an object, choose Upload, and then choose Add Files. In the file selection dialog box, find the file that you want to upload, choose it, choose Open, and then choose Start Upload. You can watch the progress of the upload in the Transfer pane.

Can we use CloudFront for S3?

Storing your static content with S3 provides a lot of advantages. But to help optimize your application's performance and security while effectively managing cost, we recommend that you also set up Amazon CloudFront to work with your S3 bucket to serve and protect the content.

Is CloudFront faster than S3?

Delivering from Amazon CloudFront Now we start seeing a small improvement. With an average response time of 137ms per request, it's almost twice as fast as loading directly from S3, and slightly faster than loading directly from the server.


1 Answers

I suspect that error is relevant with the CORS options of your request.

With jQuery, this is currently my sample code that successfully uploading file to S3 via CloudFront (notice the crossDomain option). If you don't use jQuery, you can base on this to write your code:

$.ajax({
    type: 'POST',
    url: 'YourGetSignatureMethod', //return your signed url
    data: {
          fileName: yourFileName,
          expiration: yourPolicyExpirationDate
    },
    success: function (signedUrl) {
         //signedUrl= 'http://sampleId.cloudfront.net/video.mp4?Policy=examplePolicy&Signature=exampleSignature&Key-Pair-Id=exampleKey'
         let fileObject = yourGetFileFunction(); //returns File API
         let reader = new FileReader(); //using the FileReader API to read files
         reader.onload = function () {                                      
	     $.ajax({
		url: signedUrl,
		type: 'PUT',
		contentType: fileObject.type,
		data: reader.result,
		processData: false,
		crossDomain: true,
                success: function(){
                //upload success
                }
	    });
        }  
        reader.readAsArrayBuffer(fileObject);
    }
 });
like image 116
Harry Avatar answered Dec 10 '22 07:12

Harry