AWS IAM ARN and wildcard - amazon-web-services

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

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?

How to prevent IAM user from seeing full list of lambda functions?

{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ReadOnlyPermissions",
"Effect": "Allow",
"Action": [
"lambda:GetAccountSettings",
"lambda:GetEventSourceMapping",
"lambda:GetFunction",
"lambda:GetFunctionConfiguration",
"lambda:GetFunctionCodeSigningConfig",
"lambda:GetFunctionConcurrency",
"lambda:ListEventSourceMappings",
"lambda:ListFunctions",
"lambda:ListTags",
"iam:ListRoles"
],
"Resource": "arn:aws:lambda:*:*:function:abc-*"
}
]
}
I have granted the above policy to the user.
But lambda:ListFunctions seems to only allow resource *.
Is there a way to make sure that only functions that start with a specific word are retrieved, or only functions with a specific tag?
No.
The Actions, resources, and condition keys for AWS Lambda - Service Authorization Reference page shows that ListFunctions does not take any Conditions.
So, it's an "all or nothing" call -- they either get a list of all functions, or they cannot view any functions.
But... you could write a Lambda function that calls ListFunctions and then only returns a subset of the results!

Restrict access to resources in AWS based on name

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-*"}}

AWS: Enforce MFA for Console users but not CLI

I am trying to give admin rights to a specific user group and enforcing MFA for the same group. MFA should be only enforced for console users though, not when using the AWS CLI.
These are the policies I have been testing with:
Policy 1 - Administrator access granted if MFA
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowAdminAccessIfSignedInWithMFA",
"Effect": "Allow",
"Action": "*",
"Resource": "*",
"Condition": {
"BoolIfExists": {
"aws:MultiFactorAuthPresent": "true"
}
}
}
]
}
Policy 2 - Still, allow the user to set up MFA in case it is not yet active
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowViewAccountInfo",
"Effect": "Allow",
"Action": "iam:ListVirtualMFADevices",
"Resource": "*"
},
{
"Sid": "AllowManageOwnVirtualMFADevice",
"Effect": "Allow",
"Action": [
"iam:CreateVirtualMFADevice",
"iam:DeleteVirtualMFADevice"
],
"Resource": "arn:aws:iam::*:mfa/${aws:username}"
},
{
"Sid": "AllowManageOwnUserMFA",
"Effect": "Allow",
"Action": [
"iam:DeactivateMFADevice",
"iam:EnableMFADevice",
"iam:GetUser",
"iam:ListMFADevices",
"iam:ResyncMFADevice"
],
"Resource": "arn:aws:iam::*:user/${aws:username}"
}
]
}
This last policy was adapted from this one.
The official documentation for aws:MultiFactorAuthPresent says, as I understand it, that the combination of "Allow", "BoolIfExists" and "true" should work well for my purpose:
This condition matches either if the key exists and is present or if the key does not exist. This combination of Allow, BoolIfExists, and true allows requests that are authenticated using MFA, or requests that cannot be authenticated using MFA. This means that AWS CLI, AWS API, and AWS SDK operations are allowed when the requester uses their long-term access keys. This combination does not allow requests from temporary credentials that could, but do not include MFA.
If you are wondering why I'm not using any (seemingly simpler) policy containing a "Deny" effect, like:
"Effect" : "Deny",
"Condition" : { "BoolIfExists" : { "aws:MultiFactorAuthPresent" : "false" } }
...the reason is:
This combination of Deny, BoolIfExists, and false denies requests that are not authenticated using MFA. Specifically, it denies requests from temporary credentials that do not include MFA. It also denies requests that are made using long-term credentials, such as AWS CLI or AWS API operations made using access keys. The *IfExists operator checks for the presence of the aws:MultiFactorAuthPresent key and whether or not it could be present, as indicated by its existence. Use this when you want to deny any request that is not authenticated using MFA. This is more secure, but can break any code or scripts that use access keys to access the AWS CLI or AWS API.
Everything works as expected, except for when I try to access resources using the AWS CLI (with an access key).
Am I missing something or is the documentation misleading?
PS: I would like to avoid having separate user groups for console and CLI users.

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