AWS S3 Bucket policy public. How to make object private? - amazon-web-services

I've a bucket with GetObject available to everyone on full bucket(*). I want to make a few objects private(through Object level operation ACL), i.e. only the bucket owner should have read access to the object. I've gone through all available documentation, but couldn't find any possible way. Can anyone confirm is this possible or not?

You cannot use S3 Object ACLs because ACLs do not have a DENY.
You can modify your S3 policy to specify objects and deny access to individual items.
Example S3 Policy (notice that this policy forbids access to everyone for GetObject for two files):
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::mybucket/*"
},
{
"Sid": "DenyPublicReadGetObject",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": [
"arn:aws:s3:::mybucket/block_this_file",
"arn:aws:s3:::mybucket/block_this_file_too"
]
}
]
}
If you want to add a condition so that certain users can still access the objects, add a condition after the Resource section like this. This condition will allow IAM users john.wayne and bob.hope to still call GetObject.
"Resource": [
"arn:aws:s3:::mybucket/block_this_file",
"arn:aws:s3:::mybucket/block_this_file_too"
],
"Condition": {
"StringNotEquals": {
"aws:username": [
"john.wayne",
"bob.hope"
]
}
}

Related

S3 Policy Help - Full access for IAM user. Public read only access for single folder

I have an IAM user created with a policy for my bucket. With "public block access" enabled I can interact with the bucket as expected through this user.
Now I need to make a single public read-only folder using bucket policies, but I am not having any luck. I created the below policy which should
Disable all access to all principles
Enable all access for my IAM user
Enable read-only access to specific folders for all users.
{
"Id": "Policy1676746531922",
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Stmt1676745894018",
"Action": "s3:*",
"Effect": "Deny",
"Resource": "arn:aws:s3:::bucket/*",
"Principal": "*"
},
{
"Sid": "Stmt1676746261470",
"Action": "s3:*",
"Effect": "Allow",
"Resource": "arn:aws:s3:::bucket/*",
"Principal": {
"AWS": [
"arn:aws:iam::000000000:user/bucket-user"
]
}
},
{
"Sid": "Stmt1676746523001",
"Action": [
"s3:GetObject"
],
"Effect": "Allow",
"Resource": "arn:aws:s3:::bucket/read-only-folder",
"Principal": "*"
}
]
}
I guess you cannot layer up access in this way, but I am unsure how to construct what I need. If I go with a single read policy to open up one folder, I still seem to be able to access all other folders publically too:
{
"Version": "2008-10-17",
"Statement": [
{
"Sid": "AllowPublicRead",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::bucket-name/public/*"
}
]
}
I can access "/public" but can still access "/private" too.
I need a way first to lock down the entire bucket and then open up the folders I want to provide access for?
Your policy is failing because Deny always overrides an Allow.
The first statement in the policy will Deny access to the bucket for everyone (including you!).
Your second policy on arn:aws:s3:::bucket-name/public/* is the correct way to go. It will only grant anonymous access to that particular folder.
If you are able to access other folders, then either there are other policies that exist, or you are using "authenticated access" using your own AWS credentials. Make sure when you test it that you are putting a URL into a web browser that simply looks like: https://bucket-name.ap-southeast-2.s3.amazonaws.com/foo.txt

Amazon S3 bucket policy for referer condition on specific folder

I want to use condition of StringLike aws:Referer for a particular folder and make rest of the folder publicly accessible.
Here is my bucket policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AddPerm",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": [
"arn:aws:s3:::bucketName/folderName/*"
]
},
{
"Sid": "",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::bucketName/folderName/users/*",
"Condition": {
"StringLike": {
"aws:Referer": [
"https://example.com/*"
]
}
}
}
]
}
When I am using above policy, it is not working with first one.
Try with below policy:
{
"Sid": "",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::bucketName/folderName/users/*",
"Condition": {
"StringNotLike": {
"aws:Referer": [
"https://example.com/*"
]
}
}
}
The first part of your policy is granting GetObject access for anything in the folderName path of your bucket. This includes folderName/users/*.
Therefore, the second part of your policy is not being used (since the first policy is already granting access to the folderName/users/* path.
You could solve it by using different buckets, or you could convert the second policy into a Deny with StringNotLike (effectively saying that access is denied to folderName/users/* if the referer is not example.com.
Frankly, your policy looks strange because it is granting access to the entire users path hierarchy, which probably isn't what you'd want it to do. (I'm assuming you'd want to grant access only to a particular user's data based upon who is accessing your application.)
Please note that referer is not secure — it is easy to fake this value in a browser and in web-scraping softare.

Bucket policy apply to objects not owned by me? (public bucket?)

First, let me link you context:
https://stackoverflow.com/a/9285074/6347501
I'm trying to create a public bucket for some app I'm writing. I have a policy to allow PUT and GET on all items in the bucket. But, as you can see from the link above, the policy simply won't apply to any items Put into the bucket that don't give me ownership.
Is there any solution? Is it actually possible to create a truly public bucket?
Ideally every object in this bucket is accessible to everyone regardless of who uploaded it.
Heres a working policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::my-bucket/*",
"Condition": {
"StringEquals": {
"s3:x-amz-acl": "bucket-owner-full-control"
}
}
},
{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-bucket/*"
}
]
}
It denies any objects that don't use the canned ACL "bucket-owner-full-access," which are also objects that would ignore our open GetObject policy.

How to set S3 bucket policy to (mostly) private when object acl is public?

I can't work out how to set my bucket policy to achieve what I want. Any help would be much appreciated! My desired rules are:
users in my account have access via user policies, so shouldn't need access specifically granted to them
anonymous users (or anyone outside my AWS account) should have no access, except:
one folder /temp_public should have a public GetObject (i.e. if you know the URL you can get the file)
these policies should override the object ACL on the files in the bucket, as the object ACLs are sometimes set to public read.
The reason for creating the bucket policy is that many of the objects in the bucket have a public read ACL (inadvertently set when the files were uploaded, but could also happen in future so I want to override the object ACL with the bucket ACL).
Ignoring the temp_public folder, I hoped I could just do this:
{
"Version": "2008-10-17",
"Id": "Policy123456789",
"Statement": [
{
"Sid": "Stmt1",
"Effect": "Deny",
"NotPrincipal": {
"AWS": "arn:aws:iam::123456789012:root"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-bucket-name/*"
}
]
}
(where 123456789012 is my AWS account number), but I get access denied for all users with that bucket policy. I guess the NotPrincipal isn't working in this case?
thanks for any suggestions!
Rory
UPDATE: cross-posted here on AWS forums, and answered!
Many thanks to IP from AWS Forums for this answer, which I've confirmed is working for me:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::BucketName/temp_public/*"
}
]
}
This statement will give anyone Read access to objects inside temp_public folder, regardless ACLs on those files.
To override the public access on all other files, you should provide a +Deny+-type statement. The explicit Deny overrides any Allow access, so you must exclude already given permissions. so use NotResource as an exclusion mask (NOT FINAL YET, read below):
{
"Effect": "Deny",
"Principal": "*",
"Action": "s3:GetObject",
"NotResource": "arn:aws:s3:::BucketName/temp_public/*"
}
However, this will deny access to ALL users including your account too, because principal is set to "*". Therefore, you must exclude your account from this Deny (STILL NOT FINAL):
{
"Effect": "Deny",
"NotPrincipal": { "AWS": "arn:aws:iam::XXXXYYYYZZZZ:root" },
"Action": "s3:GetObject",
"NotResource": "arn:aws:s3:::BucketName/temp_public/*"
}
(where XXXXYYYYZZZZ is your 12-digit AWS account Id)
There's still problem: the statement above denies access to all IAM users (except root account).
You'd like to exclude all your IAM users too, but this is tricky. For some reasons, Amazon S3 doens't support wildcards for specifying IAM users in a bucket policy. You cannot write "arn:aws:iam::XXXXYYYYZZZZ:user/*" as Principal (it gives an error: "Invalid principal in policy"). You have to specify exact user names:
{
"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: The S3 docs suggest you can use arn:aws:iam::XXXXYYYYZZZZ:root to cover all users in the account, but that just doesn't seem to 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/*"
}
]
}

S3 bucket policy: In a Public Bucket, make a sub-folder private

I have a bucket filled with contents that need to be mostly public. However, there is one folder (aka "prefix") that should only be accessible by an authenticated IAM user.
{
"Statement": [
{
"Sid": "AllowIAMUser",
"Action": [
"s3:GetObject"
],
"Effect": "Allow",
"Resource": "arn:aws:s3:::bucket/prefix1/prefix2/private/*",
"Principal": {
"AWS": [
"arn:aws:iam::123456789012:user/bobbydroptables"
]
}
},
{
"Sid": "AllowAccessToAllExceptPrivate",
"Action": [
"s3:GetObject",
"s3:GetObjectVersion"
],
"Effect": "Allow",
"Resource": "arn:aws:s3:::bucket/*",
"Condition": {
"StringNotLike": {
"s3:prefix": "prefix1/prefix2/private/"
}
},
"Principal": {
"AWS": [
"*"
]
}
}
]
}
When I try to save this policy I get the following error messages from AWS:
Conditions do not apply to combination of actions and resources in statement -
Condition "s3:prefix"
and action "s3:GetObject"
in statement "AllowAccessToAllExceptPrivate"
Obviously this error applies specifically to the second statement. Is it not possible to use the "s3:prefix" condition with the "s3:GetObject" action?
Is it possible to take one portion of a public bucket and make it accessible only to authenticated users?
In case it matters, this bucket will only be accessed read-only via api.
This question is similar to Amazon S3 bucket policy for public restrictions only, except I am trying to solve the problem by taking a different approach.
After much digging through AWS documentation, as well as many trial and error permutations in the policy editor, I think I have found an adequate solution.
Apparently, AWS provides an option called NotResource (not found in the Policy Generator currently).
The NotResource element lets you grant or deny access to all but a few
of your resources, by allowing you to specify only those resources to
which your policy should not be applied.
With this, I do not even need to play around with conditions. This means that the following statement will work in a bucket policy:
{
"Sid": "AllowAccessToAllExceptPrivate",
"Action": [
"s3:GetObject",
"s3:GetObjectVersion"
],
"Effect": "Allow",
"NotResource": [
"arn:aws:s3:::bucket/prefix1/prefix2/private/*",
"arn:aws:s3:::bucket/prefix1/prefix2/private"
],
"Principal": {
"AWS": [
"*"
]
}
}