AWS Identity and Access Management (IAM) with Python

Posted by Drew Engelson on

With all the AWS services that are now available, our opportunities in the cloud are virtually unlimited. But using any of these services requires access to your AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY and unfortunately, these keys provides complete access to the kingdom. This may not be a problem for some, but for large enterprises, granular access control is a necessity.

Up until recently, we would have been out of luck. But fortunately Amazon released Identity and Access Management (IAM) which makes flexible access control possible. And boto makes it easy in Python.

Take this example

Say your company uses Amazon S3 store your company's image assets in a variety of S3 buckets. If you needed to grant a third party the ability to upload new images to your S3 account, they will need a set of keys. You wouldn't want to give them your main keys since not only would they gain access to all of your S3 buckets, but also your EC2 instances, RDS databases, etc. Not a good situation.

Here's where IAM comes in. With IAM, you can create a user for this specific purpose which would have it's own unique AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY key pair. Additionally, you can apply an IAM policy to restrict what this user can do... a specific S3 bucket, in this case.

Let's give it a try

In this example, we'll create a user called melvins and grant it access to an S3 bucket called houdini.

import boto

# Connect to IAM with boto
iam = boto.connect_iam(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)

# Create user
user_response = iam.create_user('melvins')

# Limit access with IAM policy
policy_json = '''{
    "Statement":[{
        "Sid":"RandomStringIdentifier",
        "Action":"s3:*",
        "Effect":"Allow",
        "Resource":"arn:aws:s3:::houdini/*"
    }]
}'''
iam.put_user_policy('melvins', 'allow_access_houdini', policy_json)

# Generate new access key pair for 'melvins'
key_response = iam.create_access_key('melvins')

We now have a new set of AWS keys with access limited to a single S3 bucket. We could have just as easily further limited it to specific action (i.e. S3:PutObject), or to other services (i.e. EC2:*).

The objects we created with boto provide us with all sorts of nifty info.

>>> import simplejson as json
>>>
>>> user = user_response.create_user_response.create_user_result.user
>>> print json.dumps(user, indent=4)
{
    "path": "/",
    "create_date": "2011-01-22T20:02:27.900Z",
    "user_id": "AIDAXXXXXXXXXXXXXKXBW",
    "arn": "arn:aws:iam::46XXXXXXXX90:user/melvins",
    "user_name": "melvins"
}
>>>
>>> key = key_response.create_access_key_response.create_access_key_result.access_key
>>> print json.dumps(key, indent=4)
{
    "status": "Active",
    "user_name": "melvins",
    "create_date": "2011-01-22T20:16:17.189Z",
    "secret_access_key": "vDskXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX2cob",
    "access_key_id": "AKIAXXXXXXXXXXXXQ5DA"
}
>>>
>>> # Provide new keys to user
>>> print 'AWS_ACCESS_KEY_ID', key.access_key_id
AWS_ACCESS_KEY_ID AKIAXXXXXXXXXXXXQ5DA
>>>
>>> print 'AWS_SECRET_ACCESS_KEY', key.secret_access_key
AWS_SECRET_ACCESS_KEY vDskXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX2cob

Using IAM groups

Suppose your have three trusted employees (Buzzo, Lorax and Dale) who require full access to your AWS account. You could give them the master key pair. But what if Lorax decides to leave the company? You would have to change your master key pair, redistribute to the remaining employees, and hope there was nothing depending on the old ones. I would grow tired of this very quickly.

A better solution is to grant each employee his own key pair (as described above). But rather than managing their policies individually, you could add them to a group and apply a group policy.

import boto

# Connect to IAM with boto
iam = boto.connect_iam(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)

# Create group
iam.create_group('admins')

# Apply full access IAM policy
policy_json = '''{
   "Statement":[{
      "Effect":"Allow",
      "Action":"*",
      "Resource":"*"
      }
   ]
}
'''
iam.put_group_policy('admins', 'allow_all', policy_json)

# Create users
iam.create_user('buzzo')
iam.create_user('lorax')
iam.create_user('dale')

# Generate access keys
iam.create_access_key('buzzo')
iam.create_access_key('lorax')
iam.create_access_key('dale')

# Add users to group
iam.add_user_to_group('admins', 'buzzo')
iam.add_user_to_group('admins', 'lorax')
iam.add_user_to_group('admins', 'dale')

So when Lorax takes off, it's just a simple matter.

iam.remove_user_from_group('admins', 'lorax')
iam.delete_user('lorax')

The moral of the story is: Quit distributing your master access keys. Use IAM. I doubt you want to learn this lesson the hard way!

Version note: boto added IAM support in 2.0b3.

Links

Re-posted from Tomatohater.com.