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/
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.
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.
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.
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.
It's not enough to have permission in bucket policies only.
Check if your user (or role) is missing s3:PutObjectAcl
permission in IAM.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With