Some "Condition"s disallowed in AWS S3 Bucket Policies? - amazon-web-services

I'd like to define an S3 bucket-level policy that restricts access to specific users (e.g. using Cognito ids). Why can't a Condition block like the following be used in a Bucket policy?
{
"Statement":[
{
"Effect":"Allow",
"Principal": "*",
"Condition": {
"StringEquals":{
"cognito-identity.amazonaws.com:aud":[
"us-east-1:12345678-abcd-abcd-abcd-123456790ab",
"us-east-1:98765432-dcba-dcba-dcba-123456790ab"
]
}
},
"Action":"s3:ListBucket",
"Resource":"arn:aws:s3:::my-bucket-name"
}
]
}
When I try, I get the errror:
Policy has an invalid condition key - cognito-identity.amazonaws.com:aud
But this block works fine (minus the Principal) in a user-level policy. I'm trying to understand what the rules are, so I don't have to blindly attempt to make changes and "see what works".
To be can refer to ${cognito-identity.amazonaws.com:sub} from a bucket policy (e.g. inside of a resource URL); but I can't us it as a condition key (as in the example above).
So: are the rules for bucket policies different from other policies? Is this documented somewhere? I'd especially love a pointer to an authoritative source here, because I suspect I may be missing some important documentation.

it seems like you can't add a cognito-id based condition in bucket level policy however this can be achieved by adding a policy to your identity pools auth role.
Assume that you want every user in an identity pool to be able to read the contents of a bucked but only specific users to write. This can be achived by following policy.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject"
],
"Resource": [
"arn:aws:s3:::<bucketname>/*"
]
},
{
"Effect": "Allow",
"Action": [
"s3:PutObject"
],
"Resource": [
"arn:aws:s3:::<bucketname>/*"
],
"Condition": {
"StringEquals": {
"cognito-identity.amazonaws.com:sub": [
"<cognito id1>",
"<conito id2>"
]
}
}
}
]
}

Related

Minio s3:ListAllMyBucket bucket policy not working?

My objective is userone buckets shoud not show to other users:
s3:ListAllMyBucket
Returns a list of all buckets owned by the authenticated sender of the request. To use this operation, you must have the s3:ListAllMyBuckets permission.
This is my policy
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:CreateBucket",
"s3:ListAllMyBuckets"
],
"Resource": [
"arn:aws:s3:::*"
]
}
]
}
s3.ListAllMyBuckets is not working i don't know why?
If i misunderstand something please let me know
This Solution works but i need to know why s3:ListAllMyBuckets not working or if misunderstand something please let me know
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:*"
],
"Resource": [
"arn:aws:s3:::prefix*"
]
}
]
}
So there's no concept of a 'bucket owner' in MinIO as there is in AWS S3. The s3:ListAllMyBuckets operation effectively grants access to the ListBuckets API operation.
For what you want, there are a few patterns you can explore:
Using prefixes in a bucket per user and configuring the resource as "arn:aws:s3:::${aws:username}"
Creating a bucket per-user and creating a corresponding policy for that user only granting access to that bucket
MinIO adopts S3's deny-by-default attitude, so as long as you explicitly state which resources a user has access to, the others will fall off on their own.

Getting "Insufficient permissions to list objects" error with S3 bucket policy

I setup a bucket policy to allow two external users arn:aws:iam::123456789012:user/user1 and arn:aws:iam::123456789012:user/user2 to access everything under a particular path in our S3 bucket - s3:my-bucket-name/path/. But the user is getting the following error when trying to access the path on AWS console:
Insufficient permissions to list objects
After you or your AWS administrator have updated your permissions to allow the s3:ListBucket action, refresh the page. Learn more about identity and access management in Amazon S3.
Here's the policy document. What am I missing here?
{
"Version": "2012-10-17",
"Id": "allowAccessToBucketPath",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::123456789012:user/user1",
"arn:aws:iam::123456789012:user/user2"
]
},
"Action": [
"s3:PutObject",
"s3:List*",
"s3:Get*"
],
"Resource": [
"arn:aws:s3:::my-bucket-name/path/*",
"arn:aws:s3:::my-bucket-name/path"
]
},
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::123456789012:user/user1",
"arn:aws:iam::123456789012:user/user2"
]
},
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::my-bucket-name",
"Condition": {
"StringLike": {
"s3:prefix": "path/*"
}
}
}
]
}
I would check if you have any ACLs enabled for your bucket. In your bucket settings, check if Object Ownership is set to "ACLs enabled", in which case I would suggest you change it to "ACLs disabled".
If that doesn't work, I would suggest using the IAM Access Analyzer to help troubleshoot -- if the Access Analyzer says that your policy does in fact allow the access you want, then that would indicate that this policy is correctly defined, and you have other configurations on your bucket preventing the access.
https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-analyzer.html

AWS Bucket Policy - limit access to a bucket with bucket policy

Be default our users have full S3 access via IAM, I have one bucket however that I need to limit access to one specific user, and block all other users.
I followed this guide here https://aws.amazon.com/premiumsupport/knowledge-center/explicit-deny-principal-elements-s3/
and made this bucket policy -
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::XXXXXXXXXXXX:user/USERWHONEEDSACCESS"
]
},
"Action": "s3:*",
"Resource": "arn:aws:s3:::NAMEOFBUCKET/*"
},
{
"Sid": "",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": "arn:aws:s3:::NAMEOFBUCKET/*",
"Condition": {
"StringNotLike": {
"aws:userid": "USERWHONEEDSACCESS:*"
}
}
}
]
}
However it no worky. Any suggestions?
You can try the following:
{
"Version": "2012-10-17",
"Statement": [
{
"Principal": {
"AWS": [
"arn:aws:iam::XXXXXXXXXXXX:user/USERWHONEEDSACCESS"
]
},
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::nameofbucket/*",
"arn:aws:s3:::nameofbucket"
],
"Effect": "Allow"
},
{
"NotPrincipal": {
"AWS": [
"arn:aws:iam::XXXXXXXXXXXX:user/USERWHONEEDSACCESS"
]
},
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::nameofbucket/*",
"arn:aws:s3:::nameofbucket"
],
"Effect": "Deny"
}
]
}
In the How to Restrict Amazon S3 Bucket Access to a Specific IAM Role blog post you can read more about using NotPrincipal and restricting access to a single IAM User, specifically:
You can use the NotPrincipal element of an IAM or S3 bucket policy to limit resource access to a specific set of users. This element allows you to block all users who are not defined in its value array, even if they have an Allow in their own IAM user policies.
To generate this policy code snippet, I used this: https://asecure.cloud/a/s3_restrict_iam_user/ and I pre-filled the iamPrincipal and bucketName parameters with your example values.
While #Rigerta 's answer will work, I think it's worthy to explain why and how you can make your policy work
If you notice, in your policy you're specifying that only that user will be able to access all objects in your bucket
"Resource": "arn:aws:s3:::NAMEOFBUCKET/*"
However, the way IAM permissions work for S3 buckets is a bit tricky. Yes, that user has access to all objects and if he/she tries to push/pull an object via cli the operation will probably succeed, although via AWS console the bucket is unreachable. It's because the user has only access to the objects in the bucket, not the bucket itself
Therefore, you need to add the bucket to your resources. Changing
"Resource": "arn:aws:s3:::NAMEOFBUCKET/*"
by
"Resource": ["arn:aws:s3:::NAMEOFBUCKET/*", "arn:aws:s3:::NAMEOFBUCKET"]
should make it work.
You can check this blogpost for an example of an IAM policy for accessing a bucket. Notice how different actions are granted to different resources
Make sure that you are using an IAM unique identifier in your condition (it should start with the letters AIDA for IAM users).
"StringNotLike": {
"aws:userid": "AIDAXXXXXXXXXXXXX:*"
}
I suspect that you have written the username in your condition because you use the same placeholder as in the Principal. The IAM User Id is distinct from the username and the arn and cannot be found through the Console, but you can for example retrieve it with the aws cli get-user command.

AWS S3 StringLike Condition preventing requests to bucket

I have the following s3 IAM policy. It is intended to allow me to copy files from or put files into a bucket below from location temp/prod/tests within the bucket.
In the policy, I have added the StringLike condition, which I had hoped would allow the permissions in the policy to allow copying and puts when the object prefix contains temp/prod/tests.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Action": [
"s3:ReplicateObject",
"s3:PutObject",
"s3:ListBucket",
"s3:GetObjectAcl",
"s3:GetObject",
"s3:GetBucketLocation",
"s3:GetBucketAcl",
"s3:DeleteObject"
],
"Resource": [
"arn:aws:s3:::MYBUCKET/temp/prod/tests/*",
"arn:aws:s3:::MYBUCKET"
],
"Condition": {
"StringLike": {
"s3:prefix": [
"temp/prod/tests/*",
"temp/prod/tests/"
]
}
}
}
]
}
My problem is that the condition prevents me from copying anything under temp/prod/tests/, or putting any new object in this bucket beneath this location.
$ aws s3 cp --recursive s3://MYBUCKET/temp/prod/tests/ /tmp
download failed: s3://MYBUCKET/temp/prod/tests/testfiles/testfile to ../../../tmp/testfiles/testfile An error occurred (AccessDenied) when calling the GetObject operation: Access Denied
And
$ aws s3 cp /tmp/test s3://MYBUCKET/temp/prod/tests/
An error occurred (AccessDenied) when calling the PutObject operation: Access Denied
If I remove the Condition, I am able to copy the files as expected.
I don't understand why the condition is not working, because as far as I can see, the requests I am making match the prefix of the condition.
Does anyone know why this is not working as I expect?
First of all, I think it is a good practice to split the rules according to resources. Some of the s3 actions require a bucket, some of them require an object. It's in the documentation to every service: https://docs.aws.amazon.com/service-authorization/latest/reference/list_amazons3.html
Furthermore, the conditions instead of proper resources make the policy even more confusing.
In theory, for uploading an object you need just PutObject, you don't even need any List action. But for various cmdline tools I am curious about how far you would get with something like:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "rule1",
"Effect": "Allow",
"Action": [
"s3:ListMultipartUploadParts",
"s3:AbortMultipartUpload",
"s3:PutObject",
"s3:GetObject",
"s3:DeleteObject"
],
"Resource": [
"arn:aws:s3:::MYBUCKET/temp/prod/tests/*",
]
},
{
"Sid": "rule2",
"Effect": "Allow",
"Action": [
"s3:ListBucket",
"s3:ListBucketMultipartUploads"
],
"Resource": [
"arn:aws:s3:::MYBUCKET",
]
}
}
}
Most of the policy is derived from this blog post Writing IAM Policies: Grant Access to User-Specific Folders in an Amazon S3 Bucket
Following policy does as you mentioned in the question
It is intended to allow me to copy files from or put files into a bucket below from location temp/prod/tests within the bucket
PLUS all the actions within the folder temp/prod/tests/*. Those can be restricted further. Like you have few permissions asigned.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowGroupToSeeBucketListInTheConsole",
"Effect": "Allow",
"Action": [
"s3:ListAllMyBuckets",
"s3:GetBucketLocation"
],
"Resource": "*"
},
{
"Sid": "AllowListingOfUserFolder",
"Action": [
"s3:ListBucket"
],
"Effect": "Allow",
"Resource": [
"arn:aws:s3::: MYBUCKET"
],
"Condition": {
"StringLike": {
"s3:prefix": [
"temp/prod/tests/*"
]
}
}
},
{
"Sid": "AllowAllS3ActionsInUserFolder",
"Effect": "Allow",
"Action": [
"s3:*"
],
"Resource": "arn:aws:s3::: MYBUCKET/temp/prod/tests/*"
}
]
}
I think part of the confusion here is your expectation that s3:prefix will be present and testable during a CopyObject operation. It's present during a ListBucket operation, and I think that may be the only operation in which it's present. Condition keys for S3 are documented, but the documentation does not appear to include a matrix of which keys are present during which API operations.
Specifically, I believe that s3:prefix will be absent during an actual CopyObject operation and that means that IAM will treat this as values do not match, hence the conditional test fails and the CopyObject operation is denied.
AWS policy evaluation logic is reasonably straighforward and well-defined but the context in which AWS global condition context keys are present is not well-defined, or at least not well-documented. It's also quite difficult to determine exactly why a given API operation was denied after the fact (i.e. which part of the aggregated policies caused the failure), which makes it difficult to write and test complex policies.
Ideally, you'd know which keys are present on which operations, but that doesn't seem to be documented. One way to deal with this is to test (see what works and what does not). Another way is to use the ...IfExists condition check, but this is really designed for use with policy keys that are optional rather than that are not even relevant. When you use StringLikeIfExists, for example:
If the policy key is present in the context of the request, process the key as specified in the policy [i.e. perform a StringLike test]. If the key is not present, evaluate the condition element as true.
In the case of your policy, I'd suggest:
use bucket resources with bucket actions and object resources with object actions (right now, you are mixing them together)
limit your prefix conditions to the ListBucket operation
no need to make GetObject or PutObject conditional, simply indicate the resource ARN for which these operations will be allowed (e.g. arn:aws:s3:::MYBUCKET/temp/prod/tests/*)
I found a solution that works with minimal change to the policy.
I added ForAllValues to the condition, and now I can copy any objects beneath temp/prod/tests/ or any of the subdirectories below temp/prod/tests/.
"Condition": {
"ForAllValues:StringLike": {
"s3:prefix": [
"temp/prod/tests/*",
"temp/prod/tests/"
]
}
}

AWS S3 IAM grant access to buckets based on tags

I'm trying to grant a group of users access to all s3-buckets with a certain tag, but no access to all others.
The policy I've cobbled together looks like this:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowListAll",
"Effect": "Allow",
"Action": [
"s3:ListAllMyBuckets"
],
"Resource": [
"arn:aws:s3:::*"
]
},
{
"Sid": "AllowAllIfGroup",
"Effect": "Allow",
"Action": [
"s3:*"
],
"Condition: : {
"StringEquals" : {
"s3.ResourceTag/allow-group": "s3-access-group"
}
},
"Resource": [
"arn:aws:s3:::*",
"arn:aws:s3:::*/*"
]
}
]
}
and I can't get it to work I have tried simulating the policy for ListBucket and ListAllMyBuckets against the arn of a tagged Bucket, ListAllMyBuckets works, ListBucket fails.
If I adapt this policy to ec2 (as in 'grant start/stop/terminate to instances if tag matches') it works like a charm.
Is this possible at all or does S3 not allow for matching buckets this way?
(further clarification: my bucket has tags "allow-group" and "AllowGroup" set, I was not sure if the dash may be a problem)
S3 does not support condition keys based on bucket tags (ResourceTag), but only on object tags.
See the full list of supported conditions keys here (Scroll down to "Condition Keys for Amazon S3"):
https://docs.aws.amazon.com/IAM/latest/UserGuide/list_amazons3.html#amazons3-policy-keys
That's why it does not work.
I did some experimentation and was also unable to obtain the result you seek.
Firstly, online references to the S3 ResourceTag are rare, but AWS re:Invent 2016: AWS S3 Deep-Dive Hands-On Workshop gives an example:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject"
],
"Resource": "arn:aws:s3:::EXAMPLE-BUCKET-NAME/*",
"Condition": {
"StringEquals": {
"S3:ResourceTag/HIPAA": "True"
}
}
}
]
}
Note that it uses S3:ResourceTag rather than S3.ResourceTag.
I tried using this logic against both a bucket tag and an object tag but was unsuccessful in getting it to work. I suspect that ResourceTag is meant to refer to an object-level tag rather than a bucket-level tag, but couldn't prove this since it failed to work in both situations.
I used a policy like this:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Statement1",
"Effect": "Allow",
"Action": [
"s3:*"
],
"Resource": [
"arn:aws:s3:::my-bucket",
"arn:aws:s3:::my-bucket/*"
],
"Condition": {
"StringEquals": {
"s3:ResourceTag/AllowGroup": "s3-access-group"
}
}
}
]
}
However, it would not give me access to an object even when both the bucket and the object had the appropriate tag.
AWS docs has a reference for all services which have support for use with AWS IAM and resource tagging here
https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_aws-services-that-work-with-iam.html
At the moment, only object level tagging in S3 is supported:
¹ Amazon S3 supports tag-based authorization for only object resources.
² Amazon S3 supports service-linked roles for Amazon S3 Storage Lens.
Digging into the docs more, it appears as though PUT and DELETE operations on objects is not supported at the time of writing: https://docs.aws.amazon.com/AmazonS3/latest/userguide/tagging-and-policies.html