Ran
Ran

Reputation: 7679

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:

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!

Upvotes: 3

Views: 3269

Answers (2)

Steffen Opel
Steffen Opel

Reputation: 64741

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.


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).

Upvotes: 2

Ran
Ran

Reputation: 7679

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 [email protected]):

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::your-service-id-number:user/[email protected]",
        "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.

Upvotes: 2

Related Questions