For one AWS S3 bucket, I would like to deny access to everyone except for one specific IAM role. I created a role-based policy to allow access and that works. But other IAM users are also able to access objects and I want to prevent this. I tried adding a bucket policy like this, which denies everyone except this principal and then allows this principal. But this policy blocks access to everyone including that role.
The other IAM users I am trying to block are attached to the built-in AdminstratorAccess policy.
{
"Version": "2012-10-17",
"Id": "PolicySecretBucket",
"Statement": [
{
"Sid": "StmtDenyAll",
"Effect": "Deny",
"NotPrincipal": {
"AWS": "arn:aws:iam::********:role/service-role/my-role"
},
"Action": "s3:*",
"Resource": "arn:aws:s3:::my-bucket/*"
},
{
"Sid": "StmtAllowLambdaBot",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::********:role/service-role/my-role"
},
"Action": "s3:*",
"Resource": "arn:aws:s3:::my-bucket/*"
}
]
}
this is how I would do it:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::MyExampleBucket",
"arn:aws:s3:::MyExampleBucket/*"
],
"Condition": {
"StringNotLike": {
"aws:userId": [
"AROAEXAMPLEID:*",
"ACCOUNT NUMBER"
]
}
}
}
]
}
this is how it works.
the user's will have an IAM policy which allows s3.* actions
we will deny all the s3 actions for the bucket MyExampleBucket for any user id but the user id of the role (and the user id of the root account in case if the role is deleted) using the bucket policy
to get the user id of the role:
aws iam get-role --role-name ROLE-NAME
And finally, why yours does not work: https://serverfault.com/a/988136
reference:
https://aws.amazon.com/blogs/security/how-to-restrict-amazon-s3-bucket-access-to-a-specific-iam-role/
Denying access to a specific bucket is actually quite difficult.
For example, an Administrator might have permissions to assume the Role, so they can still access the bucket.
You would also need to review all policies to ensure that only authorized people can use iam:PassRole to assume the role via an Amazon EC2 instance.
An safer approach would be to put the bucket in a separate AWS Account. Then, only give cross-account access to specific users (not a Role). This way, the default is that Admins have zero access and you then grant access to the desired people. There are less ways to "get around" this type of access.
Related
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.
I want to create an s3 bucket policy that only the Root Account can have full access, how can I do that?
Example:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Allow full access for root account user",
"Effect": "Allow",
"Principal": {
"AWS": "root"
},
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::ih-deploy-bucket/*",
"arn:aws:s3:::ih-deploy-bucket"
]
}
]
}
Or adding a Condition Like
"Condition": {
"StringEquals" : {"aws:username" : "rootUser"}
}
This is one of the very few (if not the only) usecase for an explicit Deny with a NotPrincipal:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"NotPrincipal": {
"AWS": "arn:aws:iam::<your-account-number>:root"
},
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::ih-deploy-bucket/*",
"arn:aws:s3:::ih-deploy-bucket"
]
}
]
}
This will explicitly deny all principals that are not (and not only) the root account user, including IAM users, assumed role sessions and federated users in that account.
And since the root user always has explicit Allows for all actions on all resources, an actual Allow is given by the root user's identity-based permissions, so the root user will have access to that bucket.
The reason why this works is that a caller identity working in your account has always multiple principals simultaneously, which are being evaluated by IAM for a policy statement:
the account principal arn:aws:iam::<your-account-number>:root
the user, assumed role or federated user principal
In the case of an explicit Allow if you only used the root account principal in a Principal rule in a policy statement, then any user in that account will match the allow and will be given access, since the account principal is always part of a user's principal list in that account.
However, in the case of a Deny with a NotPrincipal, things are a bit different. Here, the list of NotPrincipals must whitelist all principals of the caller's identity to be not denied.
This fact somewhat shines through in the AWS documentation about NotPrincipal: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_notprincipal.html
When you use NotPrincipal with Deny, you must also specify the account
ARN of the not-denied principal. Otherwise, the policy might deny
access to the entire account containing the principal. Depending on
the service that you include in your policy, AWS might validate the
account first and then the user. If an assumed-role user (someone who
is using a role) is being evaluated, AWS might validate the account
first, then the role, and then the assumed-role user.
"AWS": "root"
should be changed to
"AWS": "arn:aws:iam::<your-account-number>:root"
Like httpdigest said in this answer, the root user always has explicit Allows for all actions on all resources.
So what I blocked all permissions to all others users that are not in condition. And the root user has always access.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Block all user not in condition, but the root has permission",
"Effect": "Deny",
"Principal": {
"AWS": "*"
},
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::bucket/*",
"arn:aws:s3:::bucket"
],
"Condition": {
"NotIpAddress": {
"aws:SourceIp": "175.222.100.192"
},
"StringNotEquals": {
"aws:username": "user1"
}
}
}
]
}
I am the root user of my account and i created one new user and trying to give access to s3 via s3 bucket policy:
Here is my policy details :-
{ "Id": "Policy1542998309644", "Version": "2012-10-17", "Statement": [ { "Sid": "Stmt1542998308012", "Action": [ "s3:ListBucket" ], "Effect": "Allow", "Resource": "arn:aws:s3:::aws-bucket-demo-1", "Principal": { "AWS": [ "arn:aws:iam::213171387512:user/Dave" ] } } ]}
in IAM i have not given any access to the new user. I want to provide him access to s3 via s3 bucket policy. Actually i would like to achieve this : https://aws.amazon.com/premiumsupport/knowledge-center/s3-console-access-certain-bucket/ But not from IAM , I want to use only s3 bucket policy.
Based on the following AWS blog post (the blog shows IAM policy, but it can be adapted to a bucket policy):
How can I grant a user Amazon S3 console access to only a certain bucket?
you can make the following bucket policy:
{
"Id": "Policy1589632516440",
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Stmt1589632482887",
"Action": [
"s3:ListBucket"
],
"Effect": "Allow",
"Resource": "arn:aws:s3:::aws-bucket-demo-1",
"Principal": {
"AWS": [
"arn:aws:iam::213171387512:user/Dave"
]
}
},
{
"Sid": "Stmt1589632515136",
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Effect": "Allow",
"Resource": "arn:aws:s3:::aws-bucket-demo-1/*",
"Principal": {
"AWS": [
"arn:aws:iam::213171387512:user/Dave"
]
}
}
]
}
This will require user to url directly to the bucket:
https://s3.console.aws.amazon.com/s3/buckets/aws-bucket-demo-1/
The reason is that the user does not have permissions to list all buckets available. Thus he/she has to go directly to the one you specify.
Obviously the IAM user needs to have AWS Management Console access enabled when you create him/her in the IAM service. With Programmatic access only, IAM users can't use console and no bucket policy can change that.
You will need to use ListBuckets.
It seems like you want this user to only be able to see your bucket but not access anything in it.
I have an account for which I wish to enable cross-account access. To that end, I need an IAM policy that specifies all the accounts for which I would like to grant access as a list of Principals, for instance:
"Principal": { "AWS": ["arn:aws:iam::123456789012:root", ...more accounts here... ] }
All the accounts to which I wish to grant access are within an AWS Organization, to which accounts are added frequently. Is there a way of specifying all accounts within an Organization within a policy, without me needing to redeploy my policy when a new account is created?
It would be nice to be able to add an account to an Organization and have this account automatically added to the policy without needing to explicitly add it.
Would the aws:PrincipalOrgID condition be able to help here?:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowGetObject",
"Action": "s3:GetObject",
"Condition": {
"StringEquals": {
"aws:PrincipalOrgID": [
"o-yyyyyyyyyy"
]
}
},
"Effect": "Allow",
"Principal": {
"AWS": [
"*"
]
},
"Resource": "arn:aws:s3:::2018-Financial-Data/*"
}
]
}
See the AWS docs here for more
I have one S3 bucket in one AWS account (say arn:aws:s3:::my-test-bucket), that needs to be accessed by a IAM group that is defined in another AWS account (say arn:aws:iam::1111222333444:group/mygroup). The following access policy refuses to save, and tells that arn:aws:s3:::my-test-bucket is an invalid principal.
{
"Statement": [
{
"Action": [
"s3:ListBucket",
"s3:PutObject",
"s3:List*",
"s3:Get*"
],
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::1111222333444:group/mygroup"
},
"Resource": [
"arn:aws:s3:::my-test-bucket",
"arn:aws:s3:::my-test-bucket/*"
],
"Sid": "allow-put-for-dedicated-group"
}
],
}
I have tested by replacing the group with one of the users of the other account and this works:
{
"Statement": [
{
"Action": [
"s3:ListBucket",
"s3:PutObject",
"s3:List*",
"s3:Get*"
],
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::1111222333444:user/me"
},
"Resource": [
"arn:aws:s3:::my-test-bucket",
"arn:aws:s3:::my-test-bucket/*"
],
"Sid": "allow-put-for-dedicated-user"
}
],
}
The group is existing, I do not understand why it says it is an invalid principal. In fact it does not accept any group of my other account.
Does anyone have an explanation (and possibly a solution) to this behaviour?
Thanks in advance,
Cheers
IAM groups are not valid principals in S3 bucket policies. See this AWS forum post and this SO post for more discussion.
Here's one idea: create an IAM role (for example cross-account-s3) in account #1 (the account with the S3 bucket). That role should have a policy that allows the appropriate S3 bucket access and it should have a trust relationship that says account #2 is trusted for sts:AssumeRole. Then in account #2, delegate permission to assume the cross-account-s3 role to the relevant IAM group. This requires you to trust the IAM admins in the 2nd account to not allow the wrong users to assume the cross-account-s3 role.
As jarmod said, IAM groups are not valid principles. Also jarmod's solution will work. However it is possible to reference the role that is assumed in the S3 bucket policy. This allows you to deny actions unless they are performed by that role, which then provides the visibility of who has access that you wanted or could be used to further limit the access provided. The role reference is via the Role ID, which can be obtained by the following AWS CLI command: aws iam get-role --role-name ROLE_NAME --profile PROFILE_NAME, where ROLE_NAME is the name of the role created with sts:AssumeRole and PROFILE_NAME is the AWS profile setup to access the role.
Something like the following could then be used for the S3 bucket policy:
{
"Statement": [
{
"Action": [
"s3:ListBucket",
"s3:PutObject",
"s3:List*",
"s3:Get*"
],
"Effect": "Deny",
"Principal": "*"
"Resource": [
"arn:aws:s3:::my-test-bucket",
"arn:aws:s3:::my-test-bucket/*"
],
"Sid": "deny-put-for-anyone-but-dedicated-role",
"Condition": {
"StringNotLike": {
"aws:userId": [
"ROLE_ID:*"
]
}
}
}
],
}
More details about this can be found in this blog post, which includes using userId to limit access to a user.