I am trying to setup IAM roles for all of my AWS resources. I have a role defined ("default") that I want set on all instances. This role lets it download needed files from a specific S3 bucket as well as get info about instances and volumes.
For some, not all, instances I want to give more abilities such as launch an instance, terminate instance, or get/put access to other S3 buckets.
There are several cases like this. Essentially every role need "default" (see above) role abilities and some instances need various extended abilities.
I can't seem to find any way to share policies across roles or anything similar. Is my only option to create multiple roles and repeat the shared abilities?
Sharing policies across roles is possible indirectly by means of 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, ... ],
}
}
Like this you only need to manage your policies centrally and can update the association with specific IAM entities (users, groups, roles) right there in a source code controlled fashion.
There's much more to CloudFormation of course, it's a very powerful tool (see Getting Started with AWS CloudFormation).
Related
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.
I have an IAM group called "devops" to which I want to apply a policy that will grant members of that group full access to EC2 instances tagged "Class=devops", and no access to any other EC2 instances. I found this great knowledge center article by Amazon which put me on the right path: https://aws.amazon.com/premiumsupport/knowledge-center/iam-ec2-resource-tags/.
The problem as I see it stems from the "Note" about halfway down that page:
"Full control" extends to all actions within the EC2 namespace with the exception of those Amazon EC2 API actions that currently do not support resource-level permissions. For more information, see Unsupported Resource-Level Permissions in the Amazon EC2 API Reference.
If you follow the link in the note to the list of unsupported resource-level permissions, you'll find that it's dozens of items long. You'll also find this statement:
All Amazon EC2 actions can be used in an IAM policy to either grant or deny users permission to use that action. However, not all Amazon EC2 actions support resource-level permissions, which enable you to specify the resources on which an action can be performed. The following Amazon EC2 API actions currently do not support resource-level permissions; therefore, to use these actions in an IAM policy, you must grant users permission to use all resources for the action by using a * wildcard for the Resource element in your statement.
In order to grant "allow" permissions to all of these.
If I wanted to grant permissions in this policy to all of those actions which don't support resource-level permissions, my policy would be hundreds of lines long! Is there a better and more concise way to do this?
There is one simple shortcut. A lot of the actions start with the same word such as "Describe". You can cover this list with a wildcard. Example, "Action" : "ec2:Describe*".
Just be careful with actions that will then override your other policy sections that DENY actions for specific resources.
I'd like to create a user in IAM that can basically do anything (create, modify, delete) to resources that are created by that user itself.
This would include creation of other roles and policies...but again only such ones that would allow controlling resources created by the parent user itself.
The purpose is to be able to create a CloudFormation template that can be run by a non admin user but still create all resources required (including things like instance profiles and lambda execution roles). All such resources could then only be managed by the owning user, thus allowing for autonomy and isolation.
I have a feeling this could be accomplished with conditions in the policy document, but not sure exactly how.
This is by no means perfect solution, and I'm not sure if that is what you need, but I recently did something similar and this is how I solved it:
We have a role that has AmazonElasticMapReduceFullAccess and Cloudformation read-only policies (managed by amazon) and one additional custom policy with coloudformation:DeleteStack permission (for deleting the EMR cluster resources).
You can restrict IAM policies on resource level. For example, the custom policy for deleting stacks looks like this:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"cloudformation:DeleteStack"
],
"Resource": "arn:aws:cloudformation:*:*:stack/EMRCluster*"
}
]
}
The way it works is that when the user needs an EMR cluster, they assume the role and create a stack named EMRCluster<date>-<UUID> and when they are done they remove the cluster resources using Cloudformation. This is, strictly speaking, not really necessary, since the user already has the EMR full access and can remove the resources (not only his) from EMR web console or via boto3 EMR API... It just makes things easier and allows the user to just do a single call to Cloudformation instead of managing EMR directly. It may look a bit funny to create and delete clusters with Cloudformation instead of directly, but it is much easier to manage a single JSON template than your custom configuration...
If you don't like that your user should have the entire EMR full access permission (quite a lot), I suggest that you play around with the EMR full access policy to allow user to create only certain resources and restrict removing resources in similar manner. Maybe you can give the user only a permission to call Cloudformation with certain template instead of that? I'm not sure if that would work without other permissions though...
Additionally, you can set VisibleToAllUsers=False in your template (see the docs), so only the user that created it should be able to manage the cluster.
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).
I'm trying to constrain the images which a specific IAM group can describe. If I have the following policy for my group, users in the group can describe any EC2 image:
{
"Effect": "Allow",
"Action": ["ec2:DescribeImages"],
"Resource": ["*"]
}
I'd like to only allow the group to describe a single image, but when I try setting "Resource": ["arn:aws:ec2:eu-west-1::image/ami-c37474b7"], I get exceptions when trying to describe the image as a member of the group:
AmazonServiceException Status Code: 403,
AWS Service: AmazonEC2,
AWS Request ID: 911a5ed9-37d1-4324-8493-84fba97bf9b6,
AWS Error Code: UnauthorizedOperation,
AWS Error Message: You are not authorized to perform this operation.
I got the ARN format for EC2 images from IAM Policies for EC2, but perhaps something is wrong with my ARN? I have verified that the describe image request works just fine when my resource value is "*".
Unfortunately the error message is misleading, the problem is that Resource-Level Permissions for EC2 and RDS Resources aren't yet available for all API actions, see this note from Amazon Resource Names for Amazon EC2:
Important
Currently, not all API actions support individual ARNs; we'll add support for additional API actions and ARNs for additional Amazon EC2 resources later. For information about which ARNs you can
use with which Amazon EC2 API actions, as well as supported condition
keys for each ARN, see Supported Resources and Conditions for Amazon
EC2 API Actions.
In particular, all ec2:Describe* actions are absent still from Supported Resources and Conditions for Amazon EC2 API Actions at the time of this writing, which implies that you cannot use anything but "Resource": ["*"] for ec2:DescribeImages.
The referenced page on Granting IAM Users Required Permissions for Amazon EC2 Resources also mentions that AWS will add support for additional actions, ARNs, and condition keys in 2014 - they have indeed regularly expanded resource level permission coverage over the last year or so already, but so far only for actions which create or modify resources, but not any which require read access only, something many users desire and expect for obvious reasons, including myself.