Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setting owner of objects in an S3 bucket

I have been experimenting with S3 and they have this cool feature where you can set ACL's on the content of a bucket through a bucket policy. So for instance you can have a bunch of files with the actual ACL on the file set to private but the file is made available to certain users / ip addresses / referrers through the overriding policy.

In my case I have a bunch of private content in a bucket but I want to make the files in a particular directory available to my site (e.g. Images). So I have something like this:

{
    "Version": "2008-10-17",
    "Id": "",
    "Statement": [
        {
            "Sid": "AddPerm",
            "Effect": "Allow",
            "Principal": {
                "AWS": "*"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::content-racket-fm/uploaded/images/*"
        }
    ]
}

Now we have some background I can get to the question. I recently found out here:

https://forums.aws.amazon.com/thread.jspa?threadID=78294

That bucket policies only work for files that are owned by the bucket owner. So for instance if the files ended up in the bucket through some external service like encoding.com or panda stream where they have their own user on your S3 bucket, you're going to have problems because your bucket policy won't be applied to these files (that seems like an oversight by amazon in my opinion but I am sure there is a good reason I haven't thought of)

I am using rails, is there a way to set the owner of an object in a bucket.

Edit

I guess a better question might be...

Is there a way to setup an amazon bucket so it applies bucket policy to all files regardless of owner.

like image 716
Steve Sheldon Avatar asked Dec 21 '11 15:12

Steve Sheldon


1 Answers

As it turns out another limitation of S3 is you don't seem to be able to change the owner of an object in a bucket. This makes bucket policies pretty useless in situations like this. As a work around, I had to fall back on using an ACL. You can set a public ACL using the rails AWS-SDK gem like this..

class AwsHelper

  # This method can be used to set a public acl on any object. The parameter file_path
  # will be the path to the file in the bucket minus the domain info, so if your full url was
  # http://s3.amazonaws.com/<your-bucket>/images/image1.png, file path would be
  # images/image1.png
  def self.set_public_acl(file_path)

    @bucket_path = ENV['S3_BUCKET']

    Rails.logger.warn "===> Loading S3"
    s3 = AWS::S3.new

    if(s3)
      bucket = s3.buckets[@bucket_path]

      if(bucket.exists?)
        Rails.logger.warn "===> Bucket '#{@bucket_path}' FOUND"

        key = bucket.objects[file_path]

        if(key.exists?)
          Rails.logger.warn "===> Key '#{file_path}' FOUND"

          key.acl = :public_read

          Rails.logger.warn "===> ACL Set to public read:"
          key.acl.grants.each { |grant| Rails.logger.warn "grantee => #{grant.grantee.group_uri}, permission => #{grant.permission.name}"}

          return key
        end
      end
    end
  end

end

In cases where you don't have control over the user who creates the content but you still want it private (for instance, when using some brands of web based video encoding), you can achieve this by copying the file after it has been created (your account will own the copy), delete the old one and then copy it back. Not ideal but it works.

like image 106
Steve Sheldon Avatar answered Nov 15 '22 05:11

Steve Sheldon