Conditions on the Trust Policy of an IAM Role - amazon-web-services

Can someone explain why Roles were designed by AWS to have a Principal like entire service (EC2, Lambda etc.) i.e. without the ability to associate/restrict to be assumable by a specific EC2 Instance type or a specific Lambda function - Am I missing a key AWS design concept here?
If I want to restrict a particular role to be assumable only by t2.micro EC2 instances (& no other EC2 instance family type), is this achievable in AWS? If this can be done, which permissions policy would this restriction be written?
Tried adding Condition section below to the 'Trusted Identity' policy of role but this does not work i.e. other instance types example t2.large is also able to perform actions say create a bucket (using CLI).
"Condition": {
"StringEquals": {
"ec2:InstanceType": [
"t2.micro"
]} }

No, it is not possible to put limitations in the Trust Policy.
If you only want certain IAM Roles to be used on particular instances, you would need to enforce that through the use of iam:PassRole. This is the permission that determines whether somebody has permission to pass a particular role to a service (such as an EC2 instance). Put simply: You can limit who is allowed to select an IAM Role and then trust that they know when to use it correctly.

Related

Strange behavior with IAM Roles

I created an IAM Role for EC2 called Role4EC2-FA and assigned the AmazonS3FullAccess policy to it. I was able to attach the same to the EC2 instance and access the S3 services from the EC2.
In the Trust Relationship I did change the Principal Service from ec2.amazonaws.com to s3.amazonaws.com, but still I was able to attach the same IAM Role to an EC2 instance, which should not be the case. But the good thing is that S3 service was not accessible from the EC2 this time.
Is this the expected behavior?
It is not the trust policy which decide if a role can be attached to an instance or not. It is an instance profile.
Trust policy says which service can assume this role. When you changed it to S3, EC2 was not allowed anymore to assume it, that is why it couldn't access S3.
But as you still have an instance profile, you still can attach it to instance.
https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_switch-role-ec2_instance-profiles.html

Is it possible to configure each instance in an AWS AutoScalingGroup with a IAM permission based on each instance ID?

I want to create a number of EC2 instances via an AutoScalingGroup using CDK.
AutoScalingGroup ec2Asg = AutoScalingGroup.Builder.create(this, "Ec2Asg")
.role(myEc2InstanceProfileRole)
... further config here ...
.build();
If possible, I'd like to restrict each instance in the ASG to only be able to access certain resources where the instance's ID forms part of the resource. For example:
arn:aws:ssm:REGION:ACCOUNT:parameter/<INSTANCE ID>/*
How is best to achieve this?
Unfortunately this would not be possible for what you're trying to achieve. The IAM permissions for an EC2 instance are not assigned to the instance itself, they are instead attached to an IAM entity (such as the instances IAM role).
SSM parameters do support a hierarchy so you can create a parameter such as arn:aws:ssm:REGION:ACCOUNT:parameter/InstanceRole/i-1234567/parameter and then limit the IAM role to only access resources which match the pattern arn:aws:ssm:REGION:ACCOUNT:parameter/InstanceRole/.
By doing this you can at least limit the scope for your instances in the same ASG. Also be aware that the parameters themselves would still be accessible for any IAM resources with the permissions granted to them.

AWS CloudFormation drop down for IAM Role

I'm trying to select an IAM Role from the list to attach it to EC2 instances while deploying servers. However, I'm not seeing an option to do this.
"IAMRole": {
"Description": "EC2 attached IAM role, must be an existing IAM role which will be attached to EC2 instance.",
"Type": "AWS::IAM::Role::RoleName",
"ConstraintDescription": "Must be the name of an existing IAM Role",
},
I'm only having an option to use Type: String and pass default string value.
Correct me if this is wrong or something I need to know.
Based on Parameters - AWS CloudFormation, there is no parameter type for nominating an IAM Role.
There are pre-defined types for VPC, Subnets, Security Groups, etc but none for IAM elements.
Therefore, it is not possible to present an automatically-populated drop-down list of IAM Roles when selecting parameters during the launch of an AWS CloudFormation stack.

AWS Managed Policy Vs Policy

Can someone explain to me the difference between an AWS Policy and an AWS Managed Policy in the context of Cloud Formation?
More specifically, I'm trying to define an auto scaling template where:
Each instance in an auto scale configuration is assigned an IAM Instance Role that has a policy.
The same policy is applied to the user when they try and access these instances.
I'm trying to keep duplication to a minimum and it seems like I may be able to achieve it via a Policy linked to a role, and group of users. The role can then be associated with EC2 Instance via instance profile and users can be added to the groups which in turn are assigned the policy.
Why and under what circumstances would one use a ManagedPolicy?
Thank you for your assistance.
EDIT: It seems like Role requires a policy document irrespective. So even having a separate policy won't really help? Or am I missing something?
AWS::IAM::Role only requires a trust policy. The Policy/Managed Policy can be defined separately.
The difference between AWS::IAM::ManagedPolicy and AWS::IAM::Policy is that AWS::IAM::ManagedPolicy does not require you to assign a Group, Role or User when defining it. AWS::IAM::Policy does. In your use case, you're probably fine using AWS::IAM::Policy.
If I may add, testing Policy creation using CDK v2.12.0, groups, users or roles are not required. iam.ManagedPolicy creates a policy you can share, iam.Policy is created as an inline policy.
new iam.Policy(this, 'testPolicy2', {
statements: policyDocs,
//groups: [s3UserGroup],
policyName: 'testPolicy2'
})
new iam.ManagedPolicy(this, 'testPolicy3', {
statements: policyDocs,
//groups: [s3UserGroup],
managedPolicyName: 'testPolicy3'
})

Is there a way to reuse AWS IAM permissions policy across users and EC2 instance roles?

I'm starting to use AWS IAM instance roles which is great for leveling up our security management but it adds some challenges maintaining a lightweight development flow.
The problem at hand is:
I define an AWS instance role and attach a security policy to this role. This policy specifies the permissions granted for new EC2 instances launched under this role, it's a long and complicated json document with rules such as "allow access to S3 bucket x" and "deny access to SQS y". This works well on EC2.
Next, I'd like to let developers run our code on their local boxes, when developing locally in the IDE, and use the exact same security policy as defined earlier. This is important b/c when developers produce new code I want them to test it WRT to the exact same security policy as they'd run with in production. If they run with different security policy there's a chance things will slip.
The problem is that I haven't found a way to do this. It's possible to define IAM Groups, and join the developers into the groups (e.g. "developers" group). In this group I can define an IAM security policy which applies to all developers in this group. But there's no way (that I found) to reuse the policy attached to a group in the context of an instance role. Or to use the policy attached to a role in the context of a group. (did I totally miss this?...)
So to sum up, what I want is: 1) define a security policy document once. 2) reuse this document in two places, one is in IAM instance role definition and the other is IAM groups.
Not being able to do so means I'll have to maintain two copies of a complicated JSON document (which is out of version control) for each type of service (and we have many such services) and for each environment (e.g. stage/prod). I can see how this becomes a maintenance nightmare very easily.
So far the best thing I came up with is perhaps to store the policy documents on disk, under version control, and write a tool that uses the aws api to upload the policy document to the both the instance role and the group. It's somewhat cumbersome so I was hoping for a little more agility.
Do you have a better advice for me?... Thanks!
Thanks #Steffen for pointing out CloudFormation, but I think I found a solution that works better for me.
AWS provide a Security Token Service which in short among other things, allows you to Assume a Role.
This is exactly what I was looking for since I want to define a role once (e.g. a set of AWS permissions) and then let AWS EC2 instances assume this role automatically (easy to do) as well as developer assume a role for a specific service they are developing. The developers part is a bit more involved, but I'll paste some Java code that shows how to do this below.
First when defining a role you have to say which principals are allowed to assume this role. You do so by editing the Trust Relationships section of the role (at the bottom of a role's definition page on AWS web UI)
So for example here's a Trust Relationships document that allows EC2 instances assume this role, as well as some of the users in my domain (replace your-service-id-number and your-user#example.com):
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::your-service-id-number:user/your-user#example.com",
"Service": "ec2.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
And next the Java code that assumes this role when running in local development:
This code checks whether I'm running on an EC2 instance, and if so will assume the role of the instance (or otherwise, whatever's defined by the DefaultAWSCredentialsProviderChain, but in my case, and the best practice is - the EC2 instance role). If running on a dev environment, e.g. outside of EC2 then it assumes the role as provided by roleName
AWSCredentialsProvider getCredentialsProvider(String roleName) {
if (isRunningOnEc2()) {
return new DefaultAWSCredentialsProviderChain();
}
// If not running on EC2, then assume the role provided
final AWSCredentials longLivedCredentialsProvider = new DefaultAWSCredentialsProviderChain().getCredentials(); // user credentials provided by env variables for ex.
// The String roleArn is defined at the top of the Role page titled "Role ARN" ;-)
final String roleArn = String.format("arn:aws:iam::your-service-id-number:role/%s", roleName);
final String roleSessionName = "session" + Math.random(); // not sure it's really needed but what the heck..
final STSAssumeRoleSessionCredentialsProvider credentialsProvider =
new STSAssumeRoleSessionCredentialsProvider(longLivedCredentialsProvider, roleArn, roleSessionName);
return credentialsProvider;
}
The utility isRunningOnEc2() is provided:
public static boolean isRunningOnEc2() {
try {
final InetAddress byName = InetAddress.getByName("instance-data");
return byName != null;
} catch (final UnknownHostException e) {
return false;
}
}
Using CloudFormation as Steffen suggested, might be useful in the general sense as well, mostly in order to retain consistency b/w my codebase and the actual AWS deployment, but that's something else.
One annoying point though: It's possible to define principals as actual usernames but not as Group of users, so you cannot actually say that "all developers are allowed to assume role x", but rather you have to list each and every developer specifically. This is pretty annoying, but I guess I'm not the only one with this complaint.
Update
AWS has just introduced Managed Policies for AWS Identity & Access Management, which provide a fresh approach to sharing and maintaining IAM policies across IAM entities, specifically aimed at reducing the current duplication of information and effort:
As the size and complexity of your AWS installation grows, you might find yourself editing multiple permission documents in order to add a new permission or to remove an existing one. Auditing and confirming permissions was also more difficult than necessary.
The security blog post An Easier Way to Manage Your Policies provides a walk through with more details.
The new feature is can be used via the AWS Management Console and the AWS Command Line Interface (AWS CLI) as usual (but presumably not via AWS CloudFormation yet).
Initial Answer
So far the best thing I came up with is perhaps to store the policy documents on disk, under version control, and write a tool that uses the aws api to upload the policy document to the both the instance role and the group. It's somewhat cumbersome so I was hoping for a little more agility.
A tool like this already exists and is in fact a major backing technology for many of AWS' own and 3rd party services - have a look at AWS CloudFormation, which gives developers and systems administrators an easy way to create and manage a collection of related AWS resources, provisioning and updating them in an orderly and predictable fashion.
More specifically, the AWS::IAM::Policy resource associates an IAM policy with IAM users, roles, or groups:
{
"Type": "AWS::IAM::Policy",
"Properties": {
"Groups" : [ String, ... ],
"PolicyDocument" : JSON,
"PolicyName" : String,
"Roles" : [ String, ...
"Users" : [ String, ... ],
}
}
There's much more to CloudFormation of course, it's a very powerful tool (see Getting Started with AWS CloudFormation).