89

I am able to upload an image file using:

s3 = session.resource('s3')
bucket = s3.Bucket(S3_BUCKET)
bucket.upload_file(file, key)

However, I want to make the file public too. I tried looking up for some functions to set ACL for the file but seems like boto3 have changes their API and removed some functions. Is there a way to do it in the latest release of boto3?

Adi
  • 4,149
  • 4
  • 25
  • 41

5 Answers5

144

To upload and set permission to publicly-readable in one step, you can use:

bucket.upload_file(file, key, ExtraArgs={'ACL':'public-read'})

See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/s3-uploading-files.html#the-extraargs-parameter

Bill Baker
  • 1,449
  • 2
  • 8
  • 3
  • 4
    Doesn't work with boto3, anyway: `botocore.exceptions.ParamValidationError: Parameter validation failed: Unknown parameter in input: "ExtraArgs", must be one of: ACL, Body, Bucket, CacheControl, ContentDisposition, ContentEncoding, ContentLanguage, ContentLength, ContentMD5, ContentType, Expires, GrantFullControl, GrantRead, GrantReadACP, GrantWriteACP, Key, Metadata, ServerSideEncryption, StorageClass, WebsiteRedirectLocation, SSECustomerAlgorithm, SSECustomerKey, SSECustomerKeyMD5, SSEKMSKeyId, RequestPayer, Tagging, ObjectLockMode, ObjectLockRetainUntilDate, ObjectLockLegalHoldStatus` – Dave Land May 31 '19 at 17:53
  • 2
    Worked for me with boto3 – yardstick17 Oct 08 '20 at 14:21
  • 1
    Works with boto3 and Object. `Object(bucket, key).upload_file(path, ExtraArgs={'ACL':'public-read'})` – sebaslh12 Apr 01 '22 at 17:18
  • https://stackoverflow.com/a/43023965/3191896 – Jossef Harush Kadouri Sep 24 '22 at 16:41
55

I was able to do it using objectAcl API:

s3 = boto3.resource('s3')
object_acl = s3.ObjectAcl('bucket_name','object_key')
response = object_acl.put(ACL='public-read')

For details: http://boto3.readthedocs.io/en/latest/reference/services/s3.html#objectacl

Adi
  • 4,149
  • 4
  • 25
  • 41
  • 10
    One liner if you're only updating one object `boto3.resource('s3').ObjectAcl('bucket_name','object_key').put(ACL='public-read')` – openwonk Apr 07 '18 at 02:47
  • This works as well as `ACL = 'public-read'`: `GrantRead = 'uri="http://acs.amazonaws.com/groups/global/AllUsers"'` – Dave Land May 31 '19 at 17:56
  • For anyone reading this in the future, apparently public-read is the **default**, for now. See the giant warning in https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html – Oded Jun 12 '19 at 05:15
13

Adi's way works. However, if you were like me, you might have run into an access denied issue. This is normally caused by broken permissions of the user. I fixed it by adding the following to the Action array:

"s3:GetObjectAcl",
"s3:PutObjectAcl"
Rohan Bagchi
  • 649
  • 10
  • 17
0

In the recent versions of boto, ACL is available as a regular parameter - both when using the S3 client and resource, it seems. You can just specify ACL="public_read" without having to wrap it with ExtraParams or using ObjectAcl API.

Czyzby
  • 2,999
  • 1
  • 22
  • 40
0

Set the ACL="public-read" as mentioned above.

Also, make sure your bucket policy Resource line has both the bare arn and /* arn formats. Not having them both can cause strange permissions problems.

...
"Resource": ["arn:aws:s3:::my_bucket/*", "arn:aws:s3:::my_bucket"]
joel3000
  • 1,249
  • 11
  • 22