Many thanks to the IP from the AWS forums for this answer , which, as I confirmed, works for me:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": "*", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::BucketName/temp_public/*" } ] }
This statement will give someone read access to the objects inside the temp_public folder, regardless of the ACL in these files. To override the public access to all other files, you must specify the + Deny + -type operator. An explicit ban cancels any allowed access, so you must exclude the permissions already granted. so use NotResource as an exception mask (NOT FINAL YET, read below):
{ "Effect": "Deny", "Principal": "*", "Action": "s3:GetObject", "NotResource": "arn:aws:s3:::BucketName/temp_public/*" }
However, this will prohibit access to all users, including your account, because the principal has "*" set. Therefore, you must exclude your account from this ban (STILL NOT FINAL):
{ "Effect": "Deny", "NotPrincipal": { "AWS": "arn:aws:iam::XXXXYYYYZZZZ:root" }, "Action": "s3:GetObject", "NotResource": "arn:aws:s3:::BucketName/temp_public/*" }
(where XXXXYYYYZZZZZ is your 12-digit AWS account ID)
There is still a problem: the above statement denies access to all IAM users (except the root account). You also want to exclude all IAM users, but this is difficult. For some reason, Amazon S3 does not support wildcards for specifying IAM users in bucket policies. You cannot write "arn:aws:iam::XXXXYYYYZZZZ:user/*" as the Principal (it gives the error: "Invalid policy principal"). You must specify the exact usernames:
{ "Effect": "Deny", "NotPrincipal": { "AWS": [ "arn:aws:iam::XXXXYYYYZZZZ:root", "arn:aws:iam::XXXXYYYYZZZZ:user/user1", "arn:aws:iam::XXXXYYYYZZZZ:user/user2", "arn:aws:iam::XXXXYYYYZZZZ:user/user3", "arn:aws:iam::XXXXYYYYZZZZ:user/user4" ] } "Action": "s3:GetObject", "NotResource": "arn:aws:s3:::BucketName/temp_public/*" }
NB from Rory: S3 docs suggest using arn:aws:iam::XXXXYYYYZZZZ:root to reach all users in an account, but that just doesn't work
So, the final policy will look like this:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": "*", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::BucketName/temp_public/*" }, { "Effect": "Deny", "NotPrincipal": { "AWS": [ "arn:aws:iam::XXXXYYYYZZZZ:root", "arn:aws:iam::XXXXYYYYZZZZ:user/user1", "arn:aws:iam::XXXXYYYYZZZZ:user/user2", "arn:aws:iam::XXXXYYYYZZZZ:user/user3", "arn:aws:iam::XXXXYYYYZZZZ:user/user4" ] } "Action": "s3:GetObject", "NotResource": "arn:aws:s3:::BucketName/temp_public/*" } ] }