Restrict access to resources in AWS based on name - amazon-web-services

I am trying to restrict the user to have access to only the resources starting with a particular string. For example, I would like to restrict the user with all permissions to only RDS instances starting with "new-database-change". Basically, in regex it would be "new-database-change-*". The application is far ahead and we missed using tags. Is there anyway we could do this without tags?
Something of the following would do.
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"rds:AddTagsToResource",
"rds:DescribeDBInstances",
"rds:DescribeDBClusters",
"rds:RestoreDBClusterToPointInTime",
"rds-db:connect",
"rds:CreateDBInstance",
"rds:DeleteDBInstance"
],
"Resource": "new-database-change-*"
}
The AWS currently takes the literal "*" and not the regex.

I don't think you can do this.
In reviewing Actions, resources, and condition keys for Amazon RDS - Service Authorization Reference:
AddTagsToResource does not take rds:DatabaseName as a Condition
DescribeDBInstances and DescribeDBClusters do not take any conditions -- they always returns ALL results
RestoreDBClusterToPointInTime does not take rds:DatabaseName as a Condition
Not sure about rds-db:connect -- it can accept an ARN, but not sure if it can accept a database name.

You should be able to do this with a wildcard resource and a restricted policy condition, for example:
"Resource": "*",
"Condition": {"StringLike": {"rds:DatabaseName": "new-database-change-*"}}

Related

Writing AWS Organizations SCP to properly account for info in request that may not always exist?

Our organization has tightly restricted AWS Organization Service Control Policies (SCPs) around certain actions, one of which is around Resource Access Manager (RAM). We attempted to use the following policy which we hoped would allow us to associate any accounts in our Organization and particular OU unit as principals to resource shares, and also associate the particular types of resources, Transit Gateways and PrefixLists.
{
"Sid": "AllowSpecificPrincipalRAMActions",
"Effect": "Deny",
"Action": "ram:AssociateResourceShare",
"Resource": "*",
"Condition": {
"StringNotEqualsIfExists": {
"ram:Principal": [
"arn:aws:organizations::123456789:organization/o-xxxxxx",
"arn:aws:organizations::123456789:ou/o-xxxxxx/ou-xxxx-xxxxxx",
]
}
}
},
{
"Sid": "AllowSpecificRAMResourceActions",
"Effect": "Deny",
"Action": "ram:AssociateResourceShare",
"Resource": "*",
"Condition": {
"StringNotEqualsIfExists": {
"ram:RequestedResourceType": [
"ec2:TransitGateway",
"ec2:PrefixList"
]
}
}
}
The reason we need both conditions, is because request bodies for ram:AssociateResourceShare have different information depending on if a principal association is being made to the resource share, or a resource association; we cannot always guarantee an instance of ram:AssociateResourceShare has either a ram:Principal, or a ram:RequestedResourceType.
We were confused why the policy didn't work as intended, then noticed this caveat in AWS documentation:
https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_condition_operators.html
" If you are using an "Effect": "Deny" element with a negated condition operator like StringNotEqualsIfExists, the request is still denied even if the tag is missing."
In effect, StringNotEqualsIfExists is not behaving as we need it to within a Deny, if either the ram:Principal or ram:RequestedResourceType is missing from the request (which is expected, as described), it will be denied instead of ignored.
How can we write this SCP statement to match our intent, and allow us to freely associate both principals and requested resource types?

List all instances with condition of a specific tag

My VPC has some instances, separated by tagging "Dept"(department). I then wrote a small iam policy to list all instances that share the same Tag (Dept:Sales). However, it resulted in "API error" of all resources in the EC2 dashboard.
I also tried using aws:RequestTag, aws:ResourceTag (global condition "aws" prefix) but the issue still persists.
I can list the instances if:
(1) I used other Actions (Ex: ec2:StartInstances or ec2:StopInstances).
(2) Change condition operator from "StringEquals" to "StringNotEquals" => Result: OK. From this, I understand the IAM request include "ResourceTag".
May you please explain how I can list the instances which share the specific tag?
Thanks.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:Describe*",
"ec2:Get*"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"ec2:ResourceTag/Dept": "Sales"
}
}
}
}
There are some API Action & Resource that cannot be used with the ec2:ResourceTag/tag in the condition.
For describe*:
Note that the Describe actions do not support resource-level
permissions, so you must specify them in a separate statement without
conditions. https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/control-access-with-tags.html
To learn whether an Amazon EC2 API action supports tagging, see Actions, resources, and condition keys for Amazon EC2.

AWS policy interpretation

I am trying to understand the need for the condition "home/${aws:userid}/*" . This condition actually feels like it is satisified in the "arn:aws:s3:::bucket-name/home/${aws:userid}/*" .
When we have allowed for all s3 operations in the third statement for that user. then why do we need to allow s3:listbuckets specifically for that user?
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListAllMyBuckets",
"s3:GetBucketLocation"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::bucket-name",
"Condition": {
"StringLike": {
"s3:prefix": [
"",
"home/",
"home/${aws:userid}/*"
]
}
}
},
{
"Effect": "Allow",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::bucket-name/home/${aws:userid}",
"arn:aws:s3:::bucket-name/home/${aws:userid}/*"
]
}
]
}
ref https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_examples_s3_federated-home-directory-console.html
s3:ListBucket is a bucket-level permission, while arn:aws:s3:::bucket-name/home/${aws:userid}/* is a wildcard object ARN, not a bucket ARN.
An attempt to grant s3:ListBucket will not match any Resource that isn't a bucket ARN, so the s3:* grant -- which only includes object ARNs -- does not actually allow object listings.
So this example policy does not contain any redundancy.
If this implementation still seems a bit counter-intuitive or perhaps convoluted, it does become somewhat clearer if you consider how the S3 API works on the wire. The ListObjects API action (as well as the newer ListObjectsV2) is submitted against the bucket -- there's no path in the request... or, more precisely, the path in the HTTP request is always¹ /... and the query string contains prefix= and the object key prefix where the requested listing is to be anchored.
While there's no compulsory correlation between the way the underlying API works and the way IAM policies work, it does make sense that the s3:prefix condition key is what's used to control use of the prefix parameter to ListObjects, instead of an object-level ARN, and that the bucket -- not an object key or wildcard pattern -- is the resource being accessed.
¹ always / except when it's /${bucket} as required by the old deprecated path-style URLs that are finally being phased out after a false start or two, at least for new buckets. The resource as expressed in the path component of the request URI is always the bucket itself, not the bucket plus a key prefix.
The resources are different. In the third statement, user can only access bucket-name/home/${aws:userid}. This means that when the user goes into the S3 console, and clicks bucket bucket-name it will get access denied. So user won't be able to list the bucket content, and will not see that there is home folder there. They will also not see that in bucket-name/home there is a folder with their username.
Thus, to overcome this issue, there is the second statement, which allows to list all content of ``bucket-nameand thenbucket-name/home`. This way users can navigate easily in S3 console to get to their actual home folder.
Without the second statement, users would have to type url of their home folders in browser to go to directly to it, which is not very user friendly.

AWS IAM ARN and wildcard

From the AWS IAM ARN documentation at https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html, I can see wildcard use as shown below which is quite confusing.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ManageRichardAccessKeys",
"Effect": "Allow",
"Action": [
"iam:*AccessKey*",
"iam:GetUser"
],
"Resource": "arn:aws:iam::*:user/division_abc/subdivision_xyz/Richard"
},
{
"Sid": "ListForConsole",
"Effect": "Allow",
"Action": "iam:ListUsers",
"Resource": "*"
}
]
}
In the first statement "Resource": "arn:aws:iam::*:user/division_abc/subdivision_xyz/Richard", why are we not specifying the account number and just substituting with wildcard "*" - I understand that in the context of S3 this is left blank, but over here it is wildcard - what does the wild card here really mean? The wildcard appears to give it a meaning like "any account" but isnt this incorrect?
Also, for the second statement "Resource": "*", does this mean ListUsers for any resource? which does not make any sense - should this not be something like arn:aws:iam::123456789012: indicating list users for this AWS account (123456789012)?
Assuming that the queries actually work (I didn't test them):
Yes, leaving out the account number is a 'little' dangerous because it would also be permitting the user that has this policy to manage access keys for a same-named user in a different account, but the receiving account would not honor the request so it is safe.
The ListUsers command does not actually take many parameters (just a prefix), so it's really an "all or nothing" API call. Please note that it only applies to requesting a list of users, nothing else. (That is, there is no concept of calling "ListUsers for a resource".)
See: Actions, Resources, and Condition Keys for Identity And Access Management - AWS Identity and Access Management

AWS IAM Policy grant permissions for some EC2 instances

I want to restrict access for a specific user to see just few EC2 instances. I created a new user in IAM Roles and I attached a new Policy to it. The content of that Policy is attached below. I tried to look over documentation and to do it myself like this:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:*",
"Resource": [
"arn:aws:ec2:eu-west-1:ACCOUNT_ID:instance/i-INSTANCE_ID1",
"arn:aws:ec2:eu-west-1:ACCOUNT_ID:instance/i-INSTANCE_ID2"
]
}
]
}
I placed my region,ACCOUNT_ID(the owner id, not of the new user created) and instance-id, but when I connect with that user and I go to list all Instances I got this An error occurred fetching instance data: You are not authorized to perform this operation..
After I placed the code in JSON editor, in Policy Review step I got this message:
This policy defines some actions, resources, or conditions that do not
provide permissions. To grant access, policies must have an action
that has an applicable resource or condition. For details, choose Show
remaining Learn more
The AWS documentation mention exactly the same configuration or these examples.
I assume you connect as that user in the console (but it would be the same with CLI) Here is what I think is happening:
To list all the instances, the console most probably calls the DescribeInstances API. As per the list of action/resources/tags that can be used in IAM policy, this API does not support the resource filter in IAM.
This means your user has no authorization to list instances and they will not be shown in the console. You can validate this theory by using the CLI to request the details of a specific instance id, if my hypothesis is correct, it will be authorized.
As DescribeInstances can not be restricted by resource or tags, I don't think it is possible to filter the instance list for a user.
To have the console working, you'll need to add the following statement in your IAM policy
"Statement": [
{ your existing statement },
{
"Effect": "Allow",
"Action": "ec2:DescribeInstances",
"Resource": "*"
}
]
Please report if I was right :-) The example you mentioned in your question shows exactly that : Resources = * on DescribeInstances and Resources specific InstanceId on other operations.
The previous answer is wrong, you can Conditionally allow access to ec2:DescribeInstances by tag names. It's an AWS best practice as well. Also explicitly deny access to the ec2:CreateTags and ec2:DeleteTags actions to prevent users from creating or deleting tags to take control of the instance.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:DescribeInstances",
"Resource": "*",
"Condition": {
"StringEquals": {
"ec2:ResourceTag/UserName": "${aws:username}"
}
}
},
{
"Effect": "Deny",
"Action": [
"ec2:CreateTags",
"ec2:DeleteTags"
],
"Resource": "*"
}
]
}
DescribeInstances action does not support condition.
https://docs.aws.amazon.com/service-authorization/latest/reference/list_amazonec2.html