Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I assign bucket-owner-full-control when creating an S3 object with boto3?

I'm using the Amazon boto3 library in Python to upload a file into another users bucket. The bucket policy applied to the other users bucket is configured like this

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "DelegateS3BucketList",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::uuu"
            },
            "Action": "s3:ListBucket",
            "Resource": "arn:aws:s3:::bbb"
        },
        {
            "Sid": "DelegateS3ObjectUpload",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::uuu"
            },
            "Action": [
                "s3:PutObject",
                "s3:PutObjectAcl"
            ],
            "Resource": [
                "arn:aws:s3:::bbb",
                "arn:aws:s3:::bbb/*"
            ]
        }
    ]
}

where uuu is my user id and bbb is the bucket name belonging to the other user. My user and the other user are IAM accounts belonging to different organisations. (I know this policy can be written more simply, but the intention is to add a check on the upload to block objects without appropriate permissions being created).

I can then use the following code to list all objects in the bucket and also to upload new objects to the bucket. This works, however the owner of the bucket has no access to the object due to Amazons default of making objects private to the creator of the object

import base64
import hashlib
from boto3.session import Session


access_key = "value generated by Amazon"
secret_key = "value generated by Amazon"
bucketname = "bbb"

content_bytes = b"hello world!"
content_md5 = base64.b64encode(hashlib.md5(content_bytes).digest()).decode("utf-8")
filename = "foo.txt"

sess = Session(aws_access_key_id=access_key, aws_secret_access_key=secret_key)

bucket = sess.resource("s3").Bucket(bucketname)
for o in bucket.objects.all():
    print(o)

s3 = sess.client("s3")
s3.put_object(
    Bucket=bucketname,
    Key=filename,
    Body=content_bytes,
    ContentMD5=content_md5,
    # ACL="bucket-owner-full-control"  # Uncomment this line to generate error
)

As soon as I uncomment the ACL option, the code generates an Access Denied error message. If I redirect this to point to a bucket inside my own organisation, the ACL option succeeds and the owner of the bucket is given full permission to the object.

I'm now at a loss to figure this out, especially as Amazons own advice appears to be to do it the way I have shown.

https://aws.amazon.com/premiumsupport/knowledge-center/s3-bucket-owner-access/

https://aws.amazon.com/premiumsupport/knowledge-center/s3-require-object-ownership/

like image 492
Simon Pratt Avatar asked May 05 '20 10:05

Simon Pratt


People also ask

What is bucket owner full control?

By default, in a cross-account scenario where other AWS accounts upload objects to your Amazon S3 bucket, the objects remain owned by the uploading account. When the bucket-owner-full-control ACL is added, the bucket owner has full control over any new objects that are written by other accounts.

How do I change ownership of a S3 object?

If you're trying to change object ownership for objects in an existing Amazon S3 bucket, choose the ACLs disabled option under S3 Object Ownership. This option allows the bucket owner full control over all the objects in the S3 bucket and transfers the ownership to the bucket owner's account.

What is object ownership in S3 bucket?

Posted On: Oct 2, 2020. Amazon S3 Object Ownership is a new S3 feature that enables bucket owners to automatically assume ownership of objects that are uploaded to their buckets by other AWS Accounts.

How do I change permissions on my S3 bucket?

Sign in to the AWS Management Console and open the Amazon S3 console at https://console.aws.amazon.com/s3/ . In the Buckets list, choose the name of the bucket that you want to set permissions for. Choose Permissions. Under Access control list, choose Edit.


2 Answers

It's not enough to have permission in bucket policies only.

Check if your user (or role) is missing s3:PutObjectAcl permission in IAM.

like image 95
Oleksii Donoha Avatar answered Oct 17 '22 01:10

Oleksii Donoha


When using the resource methods in boto3, there can be several different API calls being made, and it isn't always obvious which calls are being made.

In comparison, when using client methods in boto3, there is a 1-to-1 mapping between the API call that is being made in boto3, and the API call received by AWS.

Therefore, it is likely that the resource.put_object() method is calling an additional API, such as PutObjectAcl. You can confirm this by looking in AWS CloudTrail and seeing which API calls are being made from your app.

In such a case, you would need the additional s3:PutObjectAcl permission. This would be needed if the upload process first creates the object, and then updates the object's Access Control List.

When using the client methods for uploading a file, there is also the ability to specify an ACL, which I think gets applied directly rather than requiring a second API call. Thus, using the client method to create the object probably would not require this additional permission.

like image 1
John Rotenstein Avatar answered Oct 17 '22 00:10

John Rotenstein