Search code examples
securityamazon-web-servicesamazon-s3

Amazon Web Services : Setting S3 policy to allow putObject and getObject but deny listBucket


I am using getObject and putObject requests on Amazon S3 and in creating a policy for access to the bucket I discovered that if I don't allow listBucket I get an 'access denied' error.

The problem with this is that listBucket means a user can list the keys in a bucket and this presents a security threat.

Is it possible to allow getObject and putObject without allowing listBucket? or is there a workaround for this?

Here is the policy:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Stmt##",
      "Effect": "Allow",
      "Action": [
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::myBucket"
      ]
    },
    {
      "Sid": "Stmt##",
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject"
      ],
      "Resource": [
        "arn:aws:s3:::myBucket/*"
      ]
    }
  ]
}

Solution

  • From the Get Object documentation:

    You need the s3:GetObject permission for this operation. For more information, go to Specifying Permissions in a Policy in the Amazon Simple Storage Service Developer Guide. If the object you request does not exist, the error Amazon S3 returns depends on whether you also have the s3:ListBucket permission.

    I've confirmed this behavior by editing a policy that was essentially identical to yours.

    I am able to get an existing object without trouble, whether or not I have the s3:ListBucket privilege, as long as I have the s3:GetObject privilege.

    The behavior changes only if I don't also have the s3:ListBucket privilege, and I request an object that does not exist. In that case, S3 will not admit to me whether that object exists -- I'm denied access to knowledge about the existence of the object, since I'm not authorized to see the list.

    Response for a valid request to a nonexistent object, without s3:ListBucket:

    <Error>
     <Code>AccessDenied</Code>
     <Message>Access Denied</Message>
     <RequestId>xxxx</RequestId>
     <HostId>xxxx</HostId>
    </Error>
    

    Response for a valid request for the same nonexistent object, with s3:ListBucket:

    <Error>
     <Code>NoSuchKey</Code>
     <Message>The specified key does not exist.</Message>
     <Key>fakefile.txt</Key>
     <RequestId>xxxx</RequestId>
     <HostId>xxxx</HostId>
    </Error>
    

    So, on objects that don't actually exist, "access denied" is the expected response without s3:ListBucket. Otherwise, it works as expected.