iLC
iLC

Reputation: 339

Disallow a user to list directory contents of S3 bucket

I am attempting to allow multiple users access to a single S3 bucket. However they should only have access to a particular directory in that bucket.

Imagine the following

my-bucket
  - client-1
    - important-doc.txt
  - client-2
    - somefile.jpg
  - my-own-file.js

With that in mind (allowing say, client-1 access to only that directory) I have the following policy:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "s3:ListBucket",
            "Resource": "arn:aws:s3:::my-bucket"
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:GetObjectVersion"
            ],
            "Resource": "arn:aws:s3:::my-bucket/client-1/*"
        }
    ]
}

This works as you would expect, client-1 can connect to the bucket, go to their particular directory and download. However it appears they have the ability to list the directory of the entire bucket, I assume due to the s3:ListBucket permission being allowed. But if I restrict that to only the folder my Transmit app notifies me that permission is denied.

Can anyone advise me how to correctly write this permission?

Upvotes: 0

Views: 129

Answers (2)

John Rotenstein
John Rotenstein

Reputation: 269370

The first choice is how to track and authenticate the users.

Option 1: IAM Users

Normally, IAM User credentials are given to employees and applications. Policies can be applied directly against IAM Users to grant them access to resources.

In the case of granting IAM Users access to specific folders within an Amazon S3 bucket, the easiest method would be to put these users into an IAM Group and then author a policy that uses IAM Policy Variables that can automatically insert the name of the IAM User into the policy:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": ["s3:ListBucket"],
      "Effect": "Allow",
      "Resource": ["arn:aws:s3:::mybucket"],
      "Condition": {"StringLike": {"s3:prefix": ["${aws:username}/*"]}}
    },
    {
      "Action": [
        "s3:GetObject",
        "s3:PutObject"
      ],
      "Effect": "Allow",
      "Resource": ["arn:aws:s3:::mybucket/${aws:username}/*"]
    }
  ]
}

There is a limit of 5000 IAM Users in an AWS Account.

Option 2: Temporary credentials

Rather than giving IAM User 'permanent' credentials, the AWS Security Token Service (STS) can issue temporary credentials with an assigned permission policy.

The flow would typically be:

  • Users authenticate themselves to your app (eg using your own database of users, or federated access from Active Directory, or even an OpenID service)
  • Your back-end app then generates temporary credentials with the appropriate permissions (such as the policy you have shown in @jellcsc's answer)
  • The app provides these credentials to the users (or their app)
  • The users use these credentials to access the permitted AWS services

The credentials expire after a period of time and the users must reconnect to your app to obtain a new set of temporary credentials.

This is more secure because the app is responsible for ensuring authentication and granting permissions. There is less risk of accidentally granting permissions to a set of users.

Option 3: Pre-signed URLs

When a web application wishes to allow access to private objects in Amazon S3, it can generate an Amazon S3 pre-signed URLs, which is a time-limited URL that provides temporary access to a private object. It works like this:

  • Users authenticate to the web app
  • When the back-end is rendering an HTML page and wants to include a reference to a private object (eg <img src='...'>, it generates a pre-signed URL that grants temporary access to a private object
  • When the user's browser sends the URL to S3, the signature is verified and the expiry time is checked. If it is valid, then S3 returns the object.

This is common in applications like photo-sharing systems where users might want to share photos with other users, so that the security is more complex than simply looking at the directory where the image is stored.

Bottom line

If you are using IAM Users, then use Option 1 and take advantage of IAM Policy Variables to write one policy that will grant appropriate access to each user. However, consider carefully whether giving IAM User access to external people is acceptable within your security posture.

Upvotes: 1

jellycsc
jellycsc

Reputation: 12259

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "VisualEditor0",
      "Effect": "Allow",
      "Action": "s3:ListBucket",
      "Resource": "arn:aws:s3:::my-bucket",
      "Condition": {
        "StringEquals": {
          "s3:prefix": [
            "client-1"
          ],
          "s3:delimiter": [
            "/"
          ]
        }
      }
    },
    {
      "Sid": "VisualEditor1",
      "Effect": "Allow",
      "Action": "s3:ListBucket",
      "Resource": "arn:aws:s3:::my-bucket",
      "Condition": {
        "StringLike": {
          "s3:prefix": [
            "client-1/*"
          ]
        }
      }
    },
    {
      "Sid": "VisualEditor2",
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:GetObjectVersion"
      ],
      "Resource": "arn:aws:s3:::my-bucket/client-1/*"
    }
  ]
}

Upvotes: 0

Related Questions