129
votes

I have a simple bucket that looks like images.mysite.com on my S3 and other buckets containing backups, etc.

I want to allow a specific user to be able to access the images.mysite.com bucket in order to upload images. However, I DO NOT want him to see any of the other buckets; not even that they exist.

I could not make a policy that does this; every time I try something restrictive, it ends up blocking the listing of any buckets.

23
I'm voting to close this question as off-topic because it should be on SuperusersTonny Madsen
A policy could be generated here at : awspolicygen.s3.amazonaws.com/policygen.htmlSuhail Gupta
Why not just share the URL of the bucket -- https://s3.console.aws.amazon.com/s3/buckets/my-bucket-name/. This way you keep them from seeing the whole list and don't change anything on your current policy.treecoder

23 Answers

120
votes

I've been trying this for a while and finally came up with a working solution. You must use different "Resources" depending on the kind of action you're performing. Also I included some missing actions in the previous answer (like DeleteObject) and restricting some more (like PutBucketAcl).

The following IAM policy is working for me now:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:ListBucket",
        "s3:GetBucketLocation",
        "s3:ListBucketMultipartUploads"
      ],
      "Resource": "arn:aws:s3:::itnighq",
      "Condition": {}
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:AbortMultipartUpload",
        "s3:DeleteObject",
        "s3:DeleteObjectVersion",
        "s3:GetObject",
        "s3:GetObjectAcl",
        "s3:GetObjectVersion",
        "s3:GetObjectVersionAcl",
        "s3:PutObject",
        "s3:PutObjectAcl",
        "s3:PutObjectVersionAcl"
      ],
      "Resource": "arn:aws:s3:::itnighq/*",
      "Condition": {}
    },
    {
      "Effect": "Allow",
      "Action": "s3:ListAllMyBuckets",
      "Resource": "*",
      "Condition": {}
    }
  ]
}

The actions regarding a bucket and those regarding objects must have different arn.

39
votes

Our use case: Provide backup space for clients of our cloud application that can be accessed by the clients directly using common S3 tools. Of course, no client should see what other clients have.

As cloudberryman explained, "You can either list all buckets or none.", so we have to come up with a work around. Background:

Granting ListAllMyBuckets rights to the user is needed so that AWS S3 console or S3Fox connect without an error message. But ListAllMyBuckets lists all buckets, regardles of the resources assigned (actually, only arn:...:::* works). That's a serious bug, if you ask me. Btw. denying ListBucket for all buckets does not prevent them from being listed, as ListBucket grants rights to list the bucket's content.

There are 3 possiblities I considered as work around. I chose the last one.

(1) use cryptic bucket names, e.g. GUIDs

Advantage: easy to set up

Disadvantage: difficult to manage, especially for the client. (imagine to find a specific GUID amoung thousands of others.) Also shows of the number of buckets = number of clients using the backup service.

(2) use one bucket with client specific folders

This is how Amazon suggests by their S3/IAM examples to provide space to access only by certain users or user groups. See: AWS Example IAM Policies

Advantage: fairly easy to set up, goes with AWS ideas

Disadvantage: forces to make the existance of all buckets public, so the client can find their "home" bucket. AWS accounting provides statistics of bucket usage, but not of folder usage, which makes it difficult to calculate cost by client.

(3) don't grant access right for ListAllMyBuckets

Advantage: you get what you want: clients can't see other client's buckets

Disadvantage: the client can't see his or her own bucket. S3Browser comes with a nice "cannot do" message and asks for the bucket name to enter. S3Fox throws an error message when connecting to the root, but allows direct navigation to the client's bucket if the bucket name is known. Amazon S3 console does not work at all.

Hope this helped to handle S3 IAM as you need it.

35
votes

It is not possible to provide access to the S3 Console without granting the ListAllMyBuckets permission.

In my case (and perhaps yours as well, future reader) an acceptable alternative is to redirect users on sign in directly to the bucket you would like them to see.

To accomplish this, append the following to your IAM sign in url: /s3/?bucket=bucket-name

Full Sign-in URL (replace your-alias and bucket-name):

https://your-alias.signin.aws.amazon.com/console/s3/?bucket=bucket-name

IAM Policy (replace bucket-name):

{
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "s3:ListAllMyBuckets",
            "Resource": "arn:aws:s3:::*"
        },
        {
            "Effect": "Allow",
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::bucket-name",
                "arn:aws:s3:::bucket-name/*"
            ]
        }
    ]
}

For more information on how to create bucket specific permissions for users, read this blog: http://mikeferrier.com/2011/10/27/granting-access-to-a-single-s3-bucket-using-amazon-iam/

22
votes

Try this policy. also take into account that there no way to let the user list only selected bucket. You can either list all buckets or none.

{
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:PutObject",
                "s3:GetObjectAcl",
                "s3:PutObjectAcl",
                "s3:ListBucket",
                "s3:GetBucketAcl",
                "s3:PutBucketAcl",
                "s3:GetBucketLocation"
            ],
            "Resource": "arn:aws:s3:::your_bucket_here/*",
            "Condition": {}
        },
        {
            "Effect": "Allow",
            "Action": "s3:ListAllMyBuckets",
            "Resource": "*",
            "Condition": {}
        }
    ]
}
11
votes

I am interpreting this question as: "Can I allow access to one bucket where any other buckets will not be accessible and thus invisible." Because, showing the name of the bucket to which no access was granted still equates to information leakage.

And the correct answer is no. The required permission is ListAllMyBuckets which will allow the user to see ALL buckets. Leaving out this permission will make the console unusable.

7
votes

There is a great way to allow users to access a specific bucket without comprising knowledge of other buckets. A group policy that is like the one below will allow users to only see "bucket a". The only catch is that the user will only ever be able to access the bucket if they connect to the given bucket endpoint. For the example below that would be bucket-a.s3.amazonaws.com. The bucket may also have to have "Authenticated Users" allowed for this to occur.

{
    "Statement": [
     {
         "Sid": "<EXAMPLE_SID>",
         "Action": [
           "s3:ListBucket",
           "s3:GetBucketLocation"
          ],
         "Effect": "Allow",
         "Resource": [
           "arn:aws:s3:::bucket-a"
         ]
     },
     {
      "Sid": "<EXAMPLE_SID>",
      "Action": "s3:*",
      "Effect": "Allow",
      "Resource": [
        "arn:aws:s3:::bucket-a/*"
      ]
     }
   ]
}

This method was tested with Cyberduck on Mac OS/X and using the s3cmd package

./s3cmd ls s3://bucket-a --access_key=ACCESS_KEY --secret_key=SECRET_KEY --bucket-locat
ion=ap-southeast-2
5
votes

Confused about why no answer was checked?

Let's break down each policy statement from above solutions:

This policy statement from applies to the contents of the bucket, but not the buck itself. This is probably not what the question asked for, because you can't see what's in the bucket.

{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:GetObjectAcl",
"s3:PutObjectAcl",
"s3:ListBucket",
"s3:GetBucketAcl",
"s3:PutBucketAcl",
"s3:GetBucketLocation"
],
"Resource": "arn:aws:s3:::your_bucket_here/*",
"Condition": {}
}

This two statement policy derived from gives readonly access to the bucket at (arn:aws:s3:::your_bucket_here/) readonly, but still allows CRUD ops on the bucket's contents (arn:aws:s3:::your_bucket_here/*).

{
  "Effect": "Allow",
  "Action": [
    "s3:ListBucket",
    "s3:GetBucketLocation",
    "s3:ListBucketMultipartUploads"
  ],
  "Resource": "arn:aws:s3:::your_bucket_here",
  "Condition": {}
},
{
  "Effect": "Allow",
  "Action": [
    "s3:AbortMultipartUpload",
    "s3:DeleteObject",
    "s3:DeleteObjectVersion",
    "s3:GetObject",
    "s3:GetObjectAcl",
    "s3:GetObjectVersion",
    "s3:GetObjectVersionAcl",
    "s3:PutObject",
    "s3:PutObjectAcl",
    "s3:PutObjectAclVersion"
  ],
  "Resource": "arn:aws:s3:::your_bucket_here/*",
  "Condition": {}
}

However, the policy includes the statement below, which allows a user see all the buckets at the endpoint. This is probably not what the question asked for.

{
"Effect": "Allow",
"Action": "s3:ListAllMyBuckets",
"Resource": "*",
"Condition": {}
}

However, the above very useful if you use a client that browsers an S3 store. If your client accesses the store and not the bucket directly, so you need access to the list of buckets at the root.

3
votes

Probably the simplest use case:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:ListBucket"],
      "Resource": ["arn:aws:s3:::bucket-name"]
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:PutObject",
        "s3:GetObject",
        "s3:DeleteObject"
      ],
      "Resource": ["arn:aws:s3:::bucket-name/*"]
    }
  ]
}
3
votes

There is easy way or workaround to do this using AWS Organizations. AWS organization allows you to have multiple user accounts. Your main account will can have multiple AWS accounts(Sub) and what ever services(s3/EC2/*) are added in whichever AWS accounts only those resources will be visible.

Please refer https://aws.amazon.com/blogs/aws/aws-organizations-policy-based-management-for-multiple-aws-accounts/ https://aws.amazon.com/organizations/

Organization On My account page

3
votes

I found this solution:
AWS FLOW:
AWS FLOW

Bucket policy:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": [
        "arn:aws:s3:::MyExampleBucket",
        "arn:aws:s3:::MyExampleBucket/*"
      ],
      "Condition": {
        "StringNotLike": {
          "aws:userId": [
            "AROAEXAMPLEID:*", #Role ID
            "111111111111" #AccountID
          ]
        }
      }
    }
  ]
}

IAM policy:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": [
        "arn:aws:s3:::MyExampleBucket",
        "arn:aws:s3:::MyExampleBucket/*"
      ],
      "Condition": {
        "StringNotLike": {
          "aws:userId": [
            "AROAEXAMPLEID:*",  #Role ID
            "AIDAEXAMPLEID",  #UserID
            "111111111111"  #AccountID
          ]
        }
      }
    }
  ]
}

aws iam get-user -–user-name USER-NAME --profile=ExampleProfile

aws iam get-role --role-name ROLE-NAME --profile=ExampleProfile

Source: https://aws.amazon.com/blogs/security/how-to-restrict-amazon-s3-bucket-access-to-a-specific-iam-role/

P.S. be careful with bucket policy, you can stay out without permissions

2
votes

As it has been well discussed above, listing only one bucket on console is not possible. But if S3 bucket's access is attached to an IAM, IAM can directly access the bucket if URL to bucket is available. S3 bucket url will be like:

https://s3.console.aws.amazon.com/s3/buckets/BucketName

Where BucketName is name of bucket IAM has access to

1
votes

I managed to get the following working. Meant that listing other buckets recieved Access Denied message. But was still able to see the bucket that I wanted if I connected with the bucket name set as path.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetBucketLocation",
        "s3:ListAllMyBuckets"
      ],
      "Resource": "arn:aws:s3:::test"
    },
    {
      "Effect": "Allow",
      "Action": ["s3:ListBucket"],
      "Resource": ["arn:aws:s3:::test"]
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:PutObject",
        "s3:GetObject",
        "s3:DeleteObject"
      ],
      "Resource": ["arn:aws:s3:::test/*"]
    }
  ]
}

I was using Cyberduck to test this connection.

1
votes

While it's not possible to restrict s3:ListAllMyBuckets action to specific buckets, as for workaround you can send them Console URL for specific bucket, e.g.

  • https://s3.console.aws.amazon.com/s3/buckets/BUCKET_NAME/

Source: Restricting list of S3 buckets from the S3 Console

In order to do that, you'll need to specify the following policy document for given user or group:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket",
                "s3:GetBucketLocation",
                "s3:ListBucketMultipartUploads"
            ],
            "Resource": [
                "arn:aws:s3:::my-bucket-1",
                "arn:aws:s3:::my-bucket-2"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:AbortMultipartUpload",
                "s3:DeleteObject",
                "s3:DeleteObjectVersion",
                "s3:GetObject",
                "s3:GetObjectAcl",
                "s3:GetObjectVersion",
                "s3:GetObjectVersionAcl",
                "s3:PutObject",
                "s3:PutObjectAcl",
                "s3:PutObjectVersionAcl"
            ],
            "Resource": [
                "arn:aws:s3:::my-bucket-1/*",
                "arn:aws:s3:::my-bucket-2/*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListAllMyBuckets"
            ],
            "Resource": "arn:aws:s3:::*"
        }
    ]
}

Where my-bucket-1 and my-bucket-2 are your buckets to give the read and write access.

Related:

1
votes

Try this policy. User cannot list any bucket, they have to use direct link to allowed bucket.

For example: s3.console.aws.amazon.com/s3/buckets/bucketname/?region=us-east-1&tab=overview

{
  "Statement": [
    {
      "Action": [
        "s3:ListBucket"
      ],
      "Effect": "Allow",
      "Resource": [
        "arn:aws:s3:::bucketname"
      ]
    },
    {
      "Action": [
        "s3:PutObject",
        "s3:GetObject"
      ],
      "Effect": "Allow",
      "Resource": [
        "arn:aws:s3:::bucketname*"
      ]
    },

  ],
  "Version": "2012-10-17"
}
1
votes

Similar to what others described above:

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

Here is however the missing piece. While it is not possible to access the bucket through S3->Home, it is possible to access only the desired bucket through a direct link.

https://s3.console.aws.amazon.com/s3/buckets/yourawsbucket/

You can find more information in the following post:

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

0
votes

The solution bellow worked for me. I wanted a policy to grant access to a specific user my_iam_user on a specific bucket my-s3-bucket.

This policy allow my user to list, delete, get e put files on a specific s3 bucket.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "ListBucket",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::123456789012:user/my_iam_user"
            },
            "Action": [
                "s3:ListBucket"
            ],
            "Resource": "arn:aws:s3:::my-s3-bucket"
        },
        {
            "Sid": "AddDeleteFiles",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::123456789012:user/my_iam_user"
            },
            "Action": [
                "s3:DeleteObject",
                "s3:GetObject",
                "s3:PutObject"
            ],
            "Resource": "arn:aws:s3:::my-s3-bucket/*"
        }
    ]
}
0
votes

I just add a similar need, solved by this :

{
  "Version": "2012-10-17",
  "Statement": [
    {
        "Effect": "Allow",
        "Action": [
            "s3:Get*",
            "s3:Put*",
            "s3:DeleteObject",
            "s3:ListBucket"
        ],
        "Resource": [
            "arn:aws:s3:::my-bucket-name",
            "arn:aws:s3:::my-bucket-name/*"
        ]
    }
  ]
}
0
votes

I use the following stuff to hide bucket's contents from other users. This not only helps to hide other buckets (don't use ListAllMyBuckets), but also folders in the same bucket, when you make one bucket, but want to have subfolders in it assigning proper permissions to IAM User/subfolder.

The following policy is applied to IAM Group and all users are in this Group. You need to take aws:userid and make a subfolder with the same name in the bucket.

UserID can be taken: aws iam get-user --user-name "user_name_for_folder_access":

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:*"
            ],
            "Resource": [
                "arn:aws:s3:::bucket_name/${aws:userid}/*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::bucket_name"
            ]
        }
    ]
}
0
votes

A nice simple solution we came up with is to block the user to login to the root directory. So they must login with remote path set to desired folder.

 {
"Statement": [
    {
        "Effect": "Allow",
        "Action": "s3:*",
        "Resource": "arn:aws:s3:::folder-name*",
        "Condition": {}
    }
]
}
0
votes

No, it's not currently possible to limit users to view selective buckets under root or anywhere else. You have only those 3 options right now.

I chose to ask the client to use the bucket name explicitly.

-1
votes

This worked perfect for me . User can upload, Download and get list of files but will not able to see files from other bucket.

 {    

"Statement": [    

{
    "Effect": "Allow",
    "Action": [
        "s3:GetObject",
        "s3:PutObject",
        "s3:GetObjectAcl",
        "s3:PutObjectAcl",
        "s3:ListBucket",
        "s3:GetBucketAcl",
        "s3:PutBucketAcl",
        "s3:GetBucketLocation"
    ],
    "Resource": "arn:aws:s3:::mybucketname/*",
    "Condition": {}
},
{
    "Effect": "Allow",
    "Action": "s3:ListAllMyBuckets",
    "Resource": "*",
    "Condition": {}
},
{
    "Effect": "Deny",
    "Action": [
        "s3:DeleteBucket",
        "s3:DeleteBucketPolicy",
        "s3:DeleteBucketWebsite",
        "s3:DeleteObject",
        "s3:DeleteObjectVersion"
    ],
    "Resource": "arn:aws:s3:::mybucketname/*",    

    "Condition": {}    

}
]
}      
-2
votes

Add a Deny clause for the bucket(s) you do not want to access. Remember that they might still be listed, but you won't be able to access the contents inside them.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "s3:*",
            "Resource": "*"
        },
        {
            "Effect": "Deny",
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::bucket-name",
                "arn:aws:s3:::bucket-name/*"
            ]
        }
    ]
}