Vivek Kalyan
Vivek Kalyan

Reputation: 11

Direct s3 boto3 File Upload: Access Denied

I am attempting to directly upload a video to s3 with my react native application through a flask server. I am following this guide from heroku.

React Native

postVideo({className, path}) {
  console.log(`posting ${className} video at ${path}`);

  const vidName = path.substring(path.indexOf('/video_')+1);
  return fetch(SERVER+'/sign_s3?file_name='+vidName+'&file_type=video/mp4', {
    method: 'GET',
  })
  .then((response) => {
    response.json().then((responseText)=> {
      this.uploadVideo({ uri: path, name: vidName, type: 'video/mp4' }, responseText.data, responseText.url);
    })
  })
  .catch((error) => {
    console.error(error);
  });
}

uploadVideo(file, s3Data, url) {
  let form = new FormData();
  for(key in s3Data.fields) {
    form.append(key, s3Data.fields[key]);
  }
  console.log(s3Data);
  form.append('file', file);
  return fetch(url, {
    method: 'PUT',
    body: form,
  })
  .then((response) => {
    console.log(response);
  })
  .catch((error) => {
    console.error(error);
  });
}

Flask server (the environment variables are stored in a .env file and loaded)

from flask import Flask, request, jsonify
import os, boto3

app = Flask(__name__)

@app.route("/")
def hello():
return "Hello World!"

@app.route("/sign_s3")
def sign_s3():
    S3_BUCKET = os.environ.get('S3_BUCKET')

    file_name = request.args.get('file_name')
    file_type = request.args.get('file_type')

    s3 = boto3.client('s3')

    presigned_post = s3.generate_presigned_post(
        Bucket = S3_BUCKET,
        Key = file_name,
        Fields = {"acl": "public-read", "Content-Type": file_type},
        Conditions = [
          {"acl": "public-read"},
          {"Content-Type": file_type}
        ],
        ExpiresIn = 3600
    )

    return jsonify({
        'data': presigned_post,
        'url': 'https://%s.s3.amazonaws.com/%s' % (S3_BUCKET, file_name)
    }) 

if __name__ == "__main__":
    app.run(host='0.0.0.0')

I set up a user with full access to s3 (it wasn't working with the root credentials as well) User Policy (full access to s3)

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "s3:*",
            "Resource": "*"
        }
    ]
}

The CORS has been setup as such

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

Error

<Error>
    <Code>
        AccessDenied
    </Code>
    <Message>
        Access Denied
    </Message>
    <RequestId>
        3399C78F3BD59FAF
    </RequestId>
    <HostId>
        mTgI5xc/iz1z69NRanZ3VfAizg6PPf0s2AdC3nE1nMqDfJYlo2trMMRUmCZMusY1hJ0xBIW21Aw=
    </HostId>
</Error>

The upload works if I set the bucket to be publicly accessible, which makes me think there must be something wrong with the signing process (since I am also sure I am giving the user enough permissions to access the bucket?)

Upvotes: 1

Views: 1380

Answers (1)

Brisk Windu
Brisk Windu

Reputation: 21

I also had this problem recently. For me it worked after changing both acl settings from "public-read" to "private".

Upvotes: 2

Related Questions