AWS – Using cross-account roles

How to Create Swap File on Ubuntu 19.10 & 19.04

Using multiple accounts to provision your resources (for example, development and production environments) provides a form of blast radius protection—even in the worst-case scenario, any issues or damages are limited to the account in which they occur, and not your entire AWS presence.

Creating and assuming roles across accounts is the best way to manage access to multiple accounts. Specific roles provide a clear and explicit declaration of permissions that can be easily reviewed, and revoked if needed. Resist the temptation to create new IAM users in each account, or to utilize IAM accounts in scenarios where you need to provide access to your account to someone from a different organization, such as a consultant.

This recipe provides a way to scale your access across many accounts, without compromising your security.

Getting ready

This recipe assumes you already have two AWS accounts created and ready to go.

In one account (the source account, referred to as account A) you will need an IAM user.

While you will need to use your account’s root credentials to set up the first role in an account, do not use them on a day-to-day basis. The root account has permissions to do anything in your account, and should only be used when necessary.

How to do it…

Follow these steps in order to create a cross-account role:

  1. Start a new template with a version and description:
AWSTemplateFormatVersion: "2010-09-09" 
Description: This template creates a role that can be assumed from another account.
  1. The template will take one parameter—the source account that can assume the role:
    Type: String 
    Description: The AWS account number to grant access to assume
      the role. 
    AllowedPattern: "[0-9]+" 
    MaxLength: "12" 
    MinLength: "12"
  1. The role itself will consist of the trust role and a sample policy:
    Type: "AWS::IAM::Role" 
      Path: "/" 
        Version: "2012-10-17" 
          - Sid: "" 
            Action: "sts:AssumeRole" 
            Effect: Allow 
              AWS: !Sub "arn:aws:iam::${SourceAccountNumber}:root" 
        - PolicyName: DoEverything 
            Version: "2012-10-17" 
              - Action: 
                  - "*" 
                Effect: Allow 
                Resource: "*" 
                Sid: DoEverything
This role has full access to the target account.
  1. Finally, we create an output that will make it easy to retrieve the target role ARN:
    Description: The Role ARN that can be assumed by the
      other account. 
    Value: !GetAtt CrossAccountRole.Arn
  1. Save the template with a known name, for example, 08-03-CrossAccountRoles.yaml.
  2. Deploy the role to the target account (that is, account B), by using the CLI tool:
      aws cloudformation create-stack \
        --stack-name CrossAccountRole \
        --template-body file://src/08-03-CrossAccountRoles.yaml \
        --parameters \
        ParameterKey=SourceAccountNumber, \
        ParameterValue=<your-source-account-number> \
        --capabilities CAPABILITY_IAM
  1. Get (just) the target role ARN from the outputs of your CloudFormation stack:
      aws cloudformation describe-stacks \
        --stack-name CrossAccountRole \
        --query 'Stacks[0].Outputs[0].OutputValue' \
        --output text
  1. In your source account (that is, account A) confirm that you can assume the target role, by manually invoking the CLI tool:
      aws sts assume-role \
        --role-arn <your-target-role-arn> \
        --role-session-name CrossAccountRole

How it works…

While cross-account roles are extremely useful for administering multiple AWS accounts, they’re not the most intuitive thing to configure. Here’s a diagram that illustrates the resources and their interactions:

Multiple cross-account roles and their interactions

The first few steps of this recipe are simply creating the target IAM role in a clear and repeatable way, using CloudFormation.

You must explicitly call out the AWS account number that will be allowed to assume this role. If you want to allow multiple accounts to assume the role, simply add more statements to the AssumeRolePolicyDocument property of the role.

The sample policy that is created in this template gives full access to the target account (because Action and Resource are both set to *). You should adjust this as appropriate, according to your needs.

Defining an output value that returns the IAM role’s ARN will make it easier to get the generated ID later in the recipe.

We then launch the template in the target account. As this template creates IAM resources, you must supply the --capabilities CAPABILITY_IAM argument. If you don’t have any existing IAM users that can launch it, use the AWS web console (after logging in with your root credentials). This means that you don’t need to bother creating IAM users in the target account.

Once you have deployed the template, you will no longer need to log in to the account manually—you can just assume the newly created role from the trusted (source) account. Using an IAM role in the target account means that your day-to-day access does not require multiple passwords, which takes work to manage and store securely. You only need to have one password—the password of your source IAM user.

After the stack has finished creating (which shouldn’t take long, as it’s only creating one resource), you can quickly extract the target role’s ARN with a describe-stacks call, combined with a specifically crafted --query argument. The JMESPath Stacks[0].Outputs[0].OutputValue query gets the OutputValue property of the first output in the first stack returned, which we know will be the target role ARN, because there is only one output in the template.

Finally, the sample assume-role command will return the credentials for the target role (that is, ACCESS_KEY_ID and SECRET_ACCESS_KEY). You can then use this in an API call, via the CLI tool, or one of the SDKs. Keep in mind that these tokens will be short-lived.

See the next section for a more convenient way to use the credentials with the CLI tool, by creating profiles.

There’s more…

Just as there are multiple ways to use roles, there are multiple ways to utilize cross-account roles.

AWS CLI profiles

One of the easiest ways to use a cross-account role, is to configure it as a profile for the AWS CLI tool to use. This means that you can quickly and easily switch accounts, just by changing the profile you use when executing your commands.

To do this, you must define the target role in the CLI configuration file. With this configuration, it is assumed that your default profile is in the source account (that is, account A).

Add the following snippet to the ~/.aws/config file on Linux and macOS computers, and to the C:\Users\[USERNAME]\.aws\config file on Windows:

[profile accountb] 
role_arn = <your-target-account-role-arn> 
source_profile = default

To use switch roles, all you need to do is pass the --profile argument along with your command:

      aws --profile accountb ...

Comments are closed.