AWS IAM Instance Profile to Administer EC2 Instances With that Profile - amazon-web-services

I have an IAM user that launches a CloudFormation stack containing an
- EC2 Instance with an
- IAM Instance Profile associated with an
- IAM Role
in the AWS::CloudFormation::Init block, the EC2 instance performs some actions that require it to call some ec2:* API actions. However, this instance should ONLY be able to call these actions for that instance itself.
The user that launches the stack has the permission to attach only a set of predefined policies and to create roles. Something like this
"CloudFormationStackLauncher": {
"Type": "AWS::IAM::ManagedPolicy",
"Properties": {
"Description": "Allows attached entity to attach and detach required policies from roles it creates.",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iam:AttachRolePolicy",
"iam:DetachRolePolicy"
],
"Resource": "*",
"Condition": {
"ArnEquals": {
"iam:PolicyArn": [
"arn:aws:iam:::policy/InstanceThatCanManageItself",
]
}
}
},
{
"Effect": "Allow",
"Action": [
"iam:CreateRole"
],
"Resource": "*"
}
]
}
}
}
So I need a definition for the policy InstanceThatCanManageItself (which needs to be defined ahead of time by a user with full admin permissions). Ideally, it would look something like:
{
"Effect": "Allow",
"Action": [
"ec2:*"
],
"Resource": [
"${ec2:SourceInstanceARN}"
]
}
But it says this policy isn't valid because the policy variable ec2:SourceInstanceARN isn't in the format of a valid ARN. I've tried using tags on the EC2 instance and adding Conditions to the policy, but it doesn't seem to work when the condition is dynamic, like this:
{
"Effect": "Allow",
"Action": [
"ec2:*"
],
"Resource": [
"*"
],
"Condition": {
"StringLike": {
"ec2:ResourceTag/role" : "${aws:userid}"
}
}
}
in the above, I'm dynamically adding a tag to the launched EC2 instance with the format "RoleId:InstanceId" as defined for the value specified for {aws:userid}, based on the description here: http://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_variables.html. This approach validates, but doesn't work...either because it's dynamic...or because the action types aren't supports for the ResourceTag context key maybe...
Is there any way to accomplish this?
Thanks.

Resource tag-based authorizations will work only for certain operations. See, for example: EC2 Supported IAM actions. For example, all Describe operations are not supported and would have to be permissioned via a separate policy statement.
As an example of operations that support resource tags, attaching/detaching volumes (see same link above for supported operations and their requirements), so the following policy would work:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:AttachVolume",
"ec2:DetachVolume"
],
"Resource": "*",
"Condition": {
"StringLike": {
"ec2:ResourceTag/policyuser": "${aws:userid}"
}
}
}
]
}
, provided both the volume and ec2 instance are tagged with tag 'policyuser' and value equal to role-id:ec2-instance-id (see IAM User Guide Reference Policy Variables), where role-id is the unique identifier of the role, obtained via e.g.
aws iam get-role --role-name rolename

Related

AWS IAM custom policy for compound values in a key not working

Trying to implement the AWS IAM tag based custom policy for below scenarios but it's not working for me.
Let's say user is having a tag where key is Environment with multiple value(- is delimiter for combine environment tag value) for this tag. Like:
There are two EC2 instance which is having Environment tag key with following value:
Instance Name Key Value
a) EC2 instance - 1 Environment Dev
b) EC2 instance - 2 Environment Prod
Below is policy JSON condition which is not working. Policy Name : A
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowStopStartEC2ForAll",
"Effect": "Allow",
"Action": [
"ec2:StartInstances",
"ec2:StopInstances"
],
"Resource": "*",
"Condition": {
"StringLike": {
"ec2:ResourceTag/Environment": "${aws:PrincipalTag/Environment}"
}
}
}
]
}
As per my requirement. User which is having policy A should be able to start/stop EC2 instance.
It appears your policy is based on Simplify granting access to your AWS resources by using tags on AWS IAM users and roles | AWS Security Blog.
However, that example was checking whether a string was equal:
"Condition": {
"StringEquals": {
"ec2:ResourceTag/CostCenter": "${aws:PrincipalTag/CostCenter}"
}
}
In your case, you wish to use StringLike. When doing so, it checks whether the right-side expression is found within the left-side expression.
In your situation, you have:
User tag: Dev-Prod
Instance tag: Dev
Therefore, the left and right sides of the expression need to be swapped, and a wildcard added to work with StringLike:
"Condition": {
"StringLike": {
"aws:PrincipalTag/Environment": "*${ec2:ResourceTag/Environment}*"
}
}
The complete policy to use is:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowStopStartEC2ForAll",
"Effect": "Allow",
"Action": [
"ec2:StartInstances",
"ec2:StopInstances"
],
"Resource": "*",
"Condition": {
"StringLike": {
"aws:PrincipalTag/Environment": "*${ec2:ResourceTag/Environment}*"
}
}
}
]
}

AWS IAM customized policy at instance level for EC2 doesn't work

Created an AWS IAM policy for a user to give permission for only stopping and starting instance but if I give a particular instance ARN resource then it doesn’t work. Default EC2 Read only permission has been given to the user to describe EC2 instances and on top of that added customized sample policy as follows:
Sample policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"ec2:Describe*",
"ec2:StopInstances",
"ec2:RunInstances",
"ec2:StartInstances"
],
"Effect": "Allow",
"Resource": "*"
This works
"Resource": "arn:aws:ec2:<region>:<account id>:instance/<instance id>"
"Resource": "arn:aws:ec2:<region>:<account id>:instance/*"
"Resource": "arn:aws:ec2:<region>::instance/*"
"Resource": "arn:aws:ec2:::instance/*"
"Resource": "arn:aws:ec2:::*"
These doesn’t work
}
]
}
Edited on 23rd January (To Show what exactly I have done)
Objective: Start and stop instance permission on a single EC2 instance to a user.
Tested different combo policies but none of them worked except "Resource": "*":
Logged in: admin_user (Full access)
Created an instance as follows:
Region: Oregon
Availability zone: us-west-2c
Instance Id: i-xxx3dxxx32xxxxxxe
Owner: xxx23xxx11
Created a user: testec2_user
Permissions given to the user:
EC2 read only (available policy)
Customized policy to permit only stop and start i-xxx38xxx32xx45 instance as follows:
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"ec2:Describe*",
"ec2:RunInstances"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"ec2:StopInstances",
"ec2:StartInstances"
],
"Effect": "Allow",
"Resource": "arn:aws:ec2:us-west-2c:xxx23xxx11:instance/i-xxx3dxxx32xxxxxxe"
}
] }
Logged in as testec2_user and tried starting up the stopped instance and received following error:
You are not authorized to perform this operation. Encoded authorization failure message
I have a plan for decoding the message received using sts decode authorization message of AWS.
DescribeInstances does not support resource-level permissions. (See Unsupported Resource-Level Permissions).
If an Amazon EC2 API action does not support resource-level
permissions, you can grant users permission to use the action, but you
have to specify a * for the resource element of your policy statement.
Read more
So, you could re-write your policy as:
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"ec2:Describe*",
"ec2:RunInstances"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"ec2:StopInstances",
"ec2:StartInstances"
],
"Effect": "Allow",
"Resource": "arn:aws:ec2:<region>:<account>:instance/<instance-id>"
}
]
}
EDIT
RunInstances needs access to several resource types besides Instance (Such as Image, Key pair, Network interface, Placement group, Security group, Snapshot, Subnet and Volume) and accepts a specific ARN format for each resource type. So, arn:aws:ec2:<region>:<account id>:instance/* would not be enough and you'll get an UnauthorizedOperation error. The "Resource" element should either be:
"Resource": "*"
Which is the easiest way, or:
"Resource": [
"arn:aws:ec2:<region>:<account>:instance/*",
"arn:aws:ec2:<region>::image/*",
"arn:aws:ec2:<region>:<account>:key-pair/*",
"arn:aws:ec2:<region>:<account>:network-interface/*",
"arn:aws:ec2:<region>:<account>:placement-group/*",
"arn:aws:ec2:<region>:<account>:security-group/*",
"arn:aws:ec2:<region>::snapshot/*",
"arn:aws:ec2:<region>:<account>:subnet/*",
"arn:aws:ec2:<region>:<account>:volume/*"
]
Which is more complex but provides fine-grained control on each resource. For example, you can allow RunInstances execution for a specific EC2 image ID or subnet ID only. For more details, see the RunInstances section here.
Additional note on PassRole Permission
When executing RunInstances, if the EC2 instance should include an instance profile, the user who launches the EC2 instance must also have the IAM PassRole permission in order to associate a role with the instance during launch. For example:
{
"Version": "2012-10-17",
"Statement": [
...
{
"Action": "iam:PassRole",
"Effect": "Allow",
"Resource":"arn:aws:iam::<account>:role/<role-name>"
}
]
}
This way, you make sure that a user doesn't pass a role to an EC2 instance where the role has more permissions than you want the user to have.
For more info on granting permission to launch EC2 instances with IAM roles, see this AWS blog article.
This is how you specify multiple resources:
…
"Effect": "Allow",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::BUCKET-NAME/home/${aws:username}",
"arn:aws:s3:::BUCKET-NAME/home/${aws:username}/*"
]
}
]
}
Source:
http://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_examples.html
EDIT:
You can also use Conditions if you want to filter out instead of including all the required resources manually.

AWS Policy Limited Administrator

I want to create a policy that allows an IAM user or role to create a set of resources (for example EC2 instances) and then manage (delete, update, etc) ONLY those resources. I hope I can accomplish this using IAM variables, wildcards, and/or conditions, but I'm not sure how.
My policy would look something like this ideally
{
"Effect": "Allow",
"Action": [
"ec2:*"
],
"Condition": [
{ "Created_By_The_Instance_Profile_In_The_CFN_Stack_That_Created_The_EC2Instance}" }
]
}
Further, what if I want to grant the EC2 instance profile to do ssm:CreateAssociation for an SSM document that was created in the same stack as the EC2 instance itself? In other words, I have a stack with an EC2 instance, and IAM Instance Profile, an IAM Role, and an SSM document and I want the EC2 instance to CreateAssociation on startup, via UserData. The user that launches the stack should have access to create these resources, but NOT to create new policies (effectively making them an administrator). I want to create a Role + Policy ahead of time and grant the stack creator the ability to attach this Role to the IAM Instance Profile Role it creates.
So, ahead of time, I (the admin), create a policy and role as such
"DeployerRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"ec2.amazonaws.com",
"lambda.amazonaws.com"
],
"AWS": "*"
},
"Action": [
"sts:AssumeRole"
]
}
]
}
}
},
"PolicyManagerPolicy": {
"Type": "AWS::IAM::ManagedPolicy",
"Properties": {
"Description": "Allows CFN deployer to attach and detach required policies.",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iam:AttachRolePolicy",
"iam:DetachRolePolicy"
],
"Resource": "*",
"Condition": {
"ArnEquals": {
"iam:PolicyArn": [
"The_Policy_Arn_I_Want_To_Create"
]
}
}
},
{
"Effect": "Allow",
"Action": [
"iam:CreateRole"
],
"Resource": "*"
}
]
},
"Roles": [ { "Ref": "DeployerRole" } ]
}
}
The "limited administrator" deployer (an IAM user in the DeployerRole) should be able to launch a stack containing an:
EC2 Instance
IAM Instance Profile
IAM Role
SSM Document
I need The_Policy_Arn_I_Want_To_Create to:
Allow ONLY the EC2 Instance created by the stack to be able to CreateAssociation ONLY with the SSM Document created by the stack. Using tags is fine, but since the Resource for the SSM document would not be able to use tags, how can I do this?
ec2 does not know about the account who created the instance (you might have that if you enable CloudTrail), a possibility will be to tag the ec2 instance when you create it with the user account and then read that from your policy as
"Condition": {"StringEquals": {"ec2:ResourceTag/<tag where the username will be>": "${aws:username}"

Granting access to S3 resources based on role name

IAM policy variables are quite cool and let you create generic policys to, for example, give users access to paths in an S3 bucket based on their username, like this:
{
"Version": "2012-10-17",
"Statement": [
{
"Action": ["s3:GetObject","s3:PutObject","s3:DeleteObject"],
"Effect": "Allow",
"Resource": "arn:aws:s3:::fooCorp-user-files/${aws:username}/*"
},
{
"Action": "s3:ListBucket",
"Effect": "Allow",
"Resource": "arn:aws:s3:::fooCorp-user-files"
}
]
}
My question is, how can this be done using roles (attached to EC2 instances) instead of user accounts?
I have a number of app servers with unique IAM user accounts that are linked to a generic policy similar to the one above. This isolates the files accessible by each user/app without creating multiple policies.
I want switch these servers to use roles instead but there doesn't seem to be an equivalent IAM variable like aws:rolename.
The docs indicate that when using a role assigned to an EC2 instance the aws:username variable isn't set and aws:userid is [role-id]:[ec2-instance-id] (which isn't helpful either).
This really seems like something you should be able to do.. or am I coming at this the wrong way?
I've been looking for the same and after a lot of searching my conclusion was that it is not possible to use the role name as a variable in a IAM policy (I'd love to be proven wrong though).
Instead, I tagged my role with a name and ended up with this:
{
"Version": "2012-10-17",
"Statement": [
{
"Action": ["s3:GetObject","s3:PutObject","s3:DeleteObject"],
"Effect": "Allow",
"Resource": "arn:aws:s3:::fooCorp-user-files/${aws:PrincipalTag/name}/*"
},
{
"Action": "s3:ListBucket",
"Effect": "Allow",
"Resource": "arn:aws:s3:::fooCorp-user-files"
}
]
}
(Cross-posted to AWS S3 IAM policy for role for restricting few instances to connect to S3 bucket based in instance tag or instance id)
Instead of using aws:SourceArn, use aws:userid!
The Request Information That You Can Use for Policy Variables documentation that you mentioned has a table showing various values of aws:userid including:
For Role assigned to an Amazon EC2 instance, it is set to role-id:ec2-instance-id
Therefore, you could use the Role ID of the role that is used to launch the Amazon EC2 instance to permit access OR the Instance ID.
For example, this one is based on a Role ID:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "SID123",
"Effect": "Allow",
"Action": [
"s3:*"
],
"Resource": [
"*"
],
"Condition": {
"StringLike": {
"aws:userid": [
"AROAIIPEUJOUGITIU5BB6*"
]
}
}
}
]
}
Of course, if you are going to assign permission based on a Role ID, then you can just as easily grant permissions within the Role itself.
This one is based on an Instance ID:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "SID123",
"Effect": "Allow",
"Action": [
"s3:*"
],
"Resource": [
"*"
],
"Condition": {
"StringLike": {
"aws:userid": [
"*:i-03c9a5f3fae4b630a"
]
}
}
}
]
}
The Instance ID will remain with the instance, but a new one will be assigned if a new instance is launched, even from the same Amazon Machine Image (AMI).

AWS S3 IAM policy for role for restricting few instances to connect to S3 bucket based in instance tag or instance id

I have a AWS S3 already associated with all the instances for read privileges to all S3 buckets. Now I need to add a policy to the roles for write privileges(Put object) so that a few of these instances can have write permissions to certain folders in the S3. Is there any way to achieve it through instance tag(better option for me) or instance id.
I tried adding an IAM policy but when I set the condition, my instances are not getting the required privileges.
The IAM policy I used is:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Stmt1456567757624",
"Effect": "Allow",
"Action": [
"s3:PutObject"
],
"Resource": "arn:aws:s3:::testbucket/testfolder1/*",
"Condition": {
"ArnEquals": {
"aws:SourceArn": "arn:aws:ec2:eu-west-1:<accountno>:instance/<instanceid1>"
}
}
},
{
"Sid": "Stmt1456567757625",
"Effect": "Allow",
"Action": [
"s3:PutObject"
],
"Resource": "arn:aws:s3:::testbucket/testfolder2/*",
"Condition": {
"ArnEquals": {
"aws:SourceArn": "arn:aws:ec2:eu-west-1:<accountno>:instance/<instanceid2>"
}
}
}
]
}
Here's an alternative, based on hints given in Granting access to S3 resources based on role name...
Instead of using aws:SourceArn, use aws:userid!
The Request Information That You Can Use for Policy Variables documentation has a table showing various values of aws:userid including:
For Role assigned to an Amazon EC2 instance, it is set to role-id:ec2-instance-id
Therefore, you could use the Role ID of the role that is used to launch the Amazon EC2 instance to permit access OR the Instance ID.
For example, this one is based on a Role ID:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "SID123",
"Effect": "Allow",
"Action": [
"s3:*"
],
"Resource": [
"*"
],
"Condition": {
"StringLike": {
"aws:userid": [
"AROAIIPEUJOUGITIU5BB6*"
]
}
}
}
]
}
Of course, if you are going to assign permission based on a Role ID, then you can just as easily grant permissions within the Role itself.
This one is based on an Instance ID:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "SID123",
"Effect": "Allow",
"Action": [
"s3:*"
],
"Resource": [
"*"
],
"Condition": {
"StringLike": {
"aws:userid": [
"*:i-03c9a5f3fae4b630a"
]
}
}
}
]
}
The Instance ID will remain with the instance, but a new one will be assigned if a new instance is launched, even from the same Amazon Machine Image (AMI).
The IAM Policy Elements Reference documentation says:
aws:SourceArn – To check the source of the request, using the Amazon Resource Name (ARN) of the source. (This value is available for only some services.)
However, the documentation does not state which services can use it.
There are examples available for its use with SQS and SNS, with a sourceARN of an Amazon S3 bucket and also using sourceARN with Lambda. However, it does not appear to be supported with Amazon EC2.