This blog post will cover everything that is there related to cross account access in AWS. Below are the things that I will cover in this blog:

  • Basics: How Cross Account Access Work and implementing it using AWS console.
  • Cross Account Access using AWS CLI.
  • Enabling Cross Account access with MFA.
  • Cross Account access requiring MFA using Python.

How Cross Account Access Work

First of all, let’s go through what is cross account access and why should we use it.

Imagine that you have two AWS accounts, let’s say Prod and Dev. You want to give IAM users in the Dev account temporary and limited access to the Prod account. By setting up cross-account access, you don’t need to create individual IAM users in each account. In addition, users don’t have to sign out of one account and sign into another in order to access resources that are in different AWS accounts.

Let’s understand how it works by diving a little bit deeper:

Imagine that your organization has multiple AWS accounts to isolate a development environment from a production environment. Users in the development account might occasionally need to access resources in the production account. For example, you might need cross-account access for a user in Dev account to have ReadOnlyAccess to Prod account.

AWS Cross Account Access using IAM Role
  • In the production account, an administrator uses IAM to create the DevReadOnly-CrossAccount role in that account. In the role, the administrator defines a trust policy that specifies the development account as a Principal, meaning that authorized users from the development account can use the DevReadOnly-CrossAccount role. The administrator then shares the appropriate information with anyone who needs to assume the role. That information is the account number and name of the role (for AWS console users) or the Amazon Resource Name (ARN) (for AWS CLI or AWS API access). The role ARN might look like arn:aws:iam::123456789012:role/DevReadOnly-CrossAccount, where the role is named DevReadOnly-CrossAccount and the role was created in account number 123456789012. Note: The administrator can optionally configure the role so that users who assume the role must first be authenticated using multi-factor authentication (MFA). I will talk more about this in upcoming section.

In the above picture you can see I am creating a role in Prod account and providing Account Id of Dev account. Also I have left Required MFA as unchecked.

Role in Prod account that grants read only access to Developers in Dev Account
  • In the development account, an administrator grants members of the Developers group permission to switch to the role. This is done by granting the Developers group permission to call the AWS Security Token Service (AWS STS) AssumeRole API for the DevReadOnly-CrossAccount role. Any IAM user that belongs to the Developers group in the development account can now switch to the DevReadOnly-CrossAccount role in the production account. Other users who are not in the developer group do not have permission to switch to the role and therefore cannot access production account.
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Action": ["sts:AssumeRole"],
    "Resource": "arn:aws:iam::Prod-account-ID:role/DevReadOnly-CrossAccount"
  }]
}

I have already created a group and an user as part of that group and assigned the above policy to the group. For more details on how to setup groups and user, see Creating IAM Groups, Attaching a Policy to IAM Group. Now, everything is set up for assuming role and access resources in Prod account. Login to your Dev account as an user who is part of Developers group (in my case the users name is Tyler-Dev) and perform the following actions.

  • The user requests switches to the role:
    • AWS console: The user chooses the account name on the navigation bar and chooses Switch Role. The user specifies the account ID (or alias) and role name.
  • The temporary credentials allow access to the AWS resource:
    • AWS console: The AWS console uses the temporary credentials on behalf of the user for all subsequent console actions, in this case, to view resources in Prod account. The console does not have access to write on any resource in the production account. When the user exits the role, the user’s permissions revert to the original permissions held before switching to the role.

You should be able to navigate through the AWS Management Console and view all the resources as you have got read only access to the Prod account. And, if you try a write operation, for example, creating a S3 bucket, you will be denied to perform it.

Cross Account Access using CLI

I have gone ahead and created a Access Key and Secret Key for my user and have already setup my box with aws-cli and configured it using aws configure. Run the below command. It returns details about the IAM user or role whose credentials are used to call the operation.

aws sts get-caller-identity

To get the temporary security credentials that you can use to use AWS resources from another account that you might not normally have access to, we use the assume-role command. It takes role arn of the destination account in which you are trying to login and a role session name as an identifier of the assumed role session.

aws sts assume-role --role-arn arn:aws:iam::123456789012:role/DevReadOnlyRead-CrossAccount --role-session-name ReadOnlyAccess

The output of the command contains an access key, secret key, and session token that you can use to authenticate to AWS.

There’s even a simpler way to run commands using AWS CLI to perform actions in other accounts using assume role. By setting up a new profile in the ~/.aws/credentials file, like shown below:

[prod-read-only]
role_arn = arn:aws:iam::123456789012:role/DevReadOnly-CrossAccount     source_profile = default 

As you can see when I use the profile prod-read-only I get the information about the STS assumed role which will be used to call the operations in prod account.

Try running any command that is a read operation using the profile that you just created and you will be able to run it, but try running any command which writes to the Prod AWS account and you will be denied.

Enabling Cross Account Access using MFA

Now, let’s say it’s mandatory for users in Dev account to authenticate using MFA before they can access anything in Prod account using assume role.

Make the below changes in the trust policy of the DevReadOnly-CrossAccount role that you created in Prod account to let users use the role only when they are authenticated using MFA.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {"AWS": "Dev-Account-ID"},
      "Action": "sts:AssumeRole",
      "Condition": {"Bool": {"aws:MultiFactorAuthPresent": true}}
    }
  ]
}

This role trust policy effectively says “I trust the IAM users from the Dev account to assume this role as long as the user is authenticated using MFA.” In the AWS management Console it will look something like this.

Trust Policy with MFA enabled

Cross Account Access requiring MFA using Python

Once you enable MFA, you will not be able to run any operation without first authenticating with MFA. You will get access denied error. Below is a python code which shows how to authenticate with MFA and then access the resources in another account. Replace the account ID’s with appropriate values.

Before running the below script you also need to setup a Virtual MFA device for the user in development account which will be used for authenticating in Prod account. See Enable Multi-Factor Authentication for setting it up.


#!/usr/bin/env python

import json
import boto3

mfatoken = input('Enter the MFA token: ')
role_arn = "arn:aws:iam::5xxxxxxxxx1:role/DevReadOnlyAccesswithMFA"
mfa_arn = "arn:aws:iam::4xxxxxxxxxx0:mfa/Tyler-Dev"
mfa_token = mfatoken
role_session_name = "AssumeRoleSession"
client = boto3.client('sts')
try:
    assumed_role_object = client.assume_role(RoleArn=role_arn,
        RoleSessionName=role_session_name,
        SerialNumber=mfa_arn,
        TokenCode=mfa_token)
    credentials=assumed_role_object['Credentials']

except:
    print(Exception)

try:
    s3_resource=boto3.resource(
      's3',
      aws_access_key_id=credentials['AccessKeyId'],
      aws_secret_access_key=credentials['SecretAccessKey'],
      aws_session_token=credentials['SessionToken'],
    )
    for bucket in s3_resource.buckets.all():
        print(bucket.name)
except:
    print(Exception)

As you can see it’s first asking for my MFA token and then listing the S3 buckets which are there in my accounts.

If you try to do any other operation apart from list or get then you will get error because you don’t have any write access to the Prod account.

Feel free to drop your questions or feedbacks in the the comments section below.

Leave a comment

Your email address will not be published. Required fields are marked *