0
votes

My scenario is as follows: I have a single server and multiple clients, which communicate via AWS S3 buckets in the following way:

  1. Clients upload files to an Upload bucket, which the server then reads.
  2. The server uploads files to a Download bucket, and the client, to which a file is destined, reads it.

Assume each client is monitoring its folder in the Download bucket, so it “knows” when a relevant file is available for downloading.

The access policy I’m trying to apply is as follows:

  1. Clients can only write to the Upload bucket. They cannot list it contents or read files from it (not even the ones they uploaded).
  2. Clients can only read from the Download bucket (they can also list the contents of the bucket). They cannot modify the Download bucket’s contents in any way.
  3. The server can read and write anything in both buckets.

Since the number of clients is virtually unlimited, I assume they all share the same AWS credentials and there is no client-specific authorization (this is handled elsewhere using tokens and is based on the write-only bucket access).

I’ve tried to apply the above using both user policies and bucket policies, using examples available online, but the clients seem to always have full access to the bucket, so I’m probably missing something major.

Is the above scenario possible, and if so – how?

2

2 Answers

1
votes

First, I should warn against sharing credentials amongst multiple clients/users/devices. This makes it very difficult to track what is happening in situations where you are trying to debug problems or protect against attacks.

The better way to grant clients access to the bucket would be:

  • Clients authenticate to your central application in some way
  • The central application generates Temporary Security Credentials using AWS Security Token Service and provides them to the client when it authenticates
  • The client uses those credentials to access Amazon S3 (they are time-limited, so they will need to request a new set of credentials after a given time period)

This way, you can track all requests that the clients are making and can control access more accurately.

When generating the temporary credentials, you can specify a policy. For your situation, this policy should be granted to the client:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowUpload",
            "Effect": "Allow",
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::upload-bucket/*"
        },
        {
            "Sid": "AllowListAndDownload",
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::download-bucket",
                "arn:aws:s3:::download-bucket/*"
            ]
        }
    ]
}

You would also grant the Server permission to use both buckets:

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

(You might want to grant other permissions, such as DeleteObject.)

You should not use Bucket Policies, since you only wish to grant permission to specific entities.

1
votes

An interesting approach would be to have a folder for every client. This could be done using the system variable : aws:userid . With this with only one policy definition you cover all users and every user has his private area for download and upload.

The policy should look like this for download:

    {
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowUpload",
            "Effect": "Allow",
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::upload-bucket/*"
            "Condition": {"StringLike": {"s3:prefix": ["${aws:userid}/*"]}}

        },
        {
            "Sid": "AllowListAndDownload",
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::download-bucket",
                "arn:aws:s3:::download-bucket/*"
            ],
            "Condition": {"StringLike": {"s3:prefix": ["${aws:userid}/*"]}}
        }
    ]
}

the aws:userid is a concatenation of the roleid and the userid . roleid is only known by you , so you need to share it with your customers. userid is specific to the login system you accept.