How to create an AWS cross account assume role script


This article shows how to create a reusable assume role script that can for example be used by AWS CodeBuild to assume a role in another AWS account.

To accomplish this we need to:

AWS multi-account setup example

In this day and age, we’re moving more towards AWS multi-account setups where workloads are being managed separately.

With a multi-account setup comes a shared services account that acts as a central hub in which AWS Codepipelines are hosted and deploy infrastructure and services to our workload accounts e.g. development, testing, acceptance, and production AWS accounts.

AWS assume role cross-account diagram example with AWS Codebuild and AWS Codepipeline
AWS assume role of cross-account diagram example with AWS Codebuild and AWS Codepipeline

The example above displays a simple multi-account setup in which a shared services account acts as a hub to deploy resources to the workload accounts.

To make it possible for the shared services account to access the other AWS accounts it needs to assume a role on the target account.

In the next step, you’ll be shown how to create an IAM role on the target AWS account.

Create an IAM role on the target AWS Account

On the target AWS account e.g. Test we need to create an IAM role that can be assumed by the source AWS account, in this case, it’s the shared services account.

As an example, we’ll use AWS CloudFormation to create a stack that can be deployed to AWS.

AWSTemplateFormatVersion: "2010-09-09"
Description: A CloudFormation template that creates a cross-account role that can be assumed by the source (shared services) account.
Parameters:
  Environment: { Description: Environment, Type: String }
  SourceAccount: { Description: Source AWS account ID, Type: String }
  S3Bucket: { Description: S3 Bucket that the shared account needs access to, Type: String }
Resources:
  CrossTargetAccountRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub crossaccount-${Environment}-role
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              AWS: !Sub arn:aws:iam::${SourceAccount}:root
            Action: sts:AssumeRole
      Path: "/"
      Policies:
        - PolicyName: S3BucketAccess
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action:
                  - s3:Get*
                  - s3:List*
                  - s3:PutObject*
                  - s3:DeleteObject*
                Resource:
                  - !Sub arn:aws:s3:::${S3Bucket}/*
                  - !Sub arn:aws:s3:::${S3Bucket}
        - PolicyName: SSMAccess
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action:
                  - ssm:PutParameter
                Resource: "*"

The CloudFormation template shows an example of an IAM role that grants the Source account access to an S3 bucket in the target account and gives the ability to create SSM Parameters.

Once you deploy it you can get the ARN of the newly created role by running the following AWS CLI command:

➜ aws iam list-roles --output text --query 'Roles[*].[Arn]'|grep crossaccount

arn:aws:iam::012345678910:role/crossaccount-tst-role

Create an IAM role on the source AWS Account

Next up we need to have an IAM role on the shared service account that assumes the role we created previously on the target account, so it can access the S3 bucket.

AWSTemplateFormatVersion: 2010-09-09
Description: A CloudFormation template that creates a role that can assume a role on a target AWS account
Parameters:
  CrossAccountRoleTestARN:
    Type: String
    Description: "The ARN of role on the target account that the source account (AWS Codebuild) assumes to access its services"
Resources:
  CodeBuildServiceRole:
  Type: AWS::IAM::Role
  Properties:
    Path: /
    AssumeRolePolicyDocument:
      Version: 2012-10-17
      Statement:
        - Effect: Allow
          Principal:
            Service: codebuild.amazonaws.com
          Action: sts:AssumeRole
    ManagedPolicyArns:
      - !Ref CrossAccountAssumePolicy
  CrossAccountAssumePolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action:
              - sts:AssumeRole
            Resource:
              - !Ref CrossAccountRoleTestARN

Here we create an IAM role that has a managed policy. Within the policy, we allow sts:AssumeRole action on the crossaccount-tst-role that we created in the previous step.

Now you can use this IAM role for AWS CodeBuild or AWS CodePipeline to automatically access resources on other accounts. But until then we need one more thing and that’s the assume role script.

Create the Assume role script

The script that we’re going to create assumes the role of the target account and uses Simple Token Service (sts) to create temporary AWS credentials.

Then it automatically creates an AWS profile that will be stored in the AWS config so that it can be used in a shell environment e.g. AWS CodeBuild step.

You can copy the code below and paste it into a shell script:

#!/bin/bash
# Usage
#
# ./assume-role.sh $CLIENT_ROLE_ARN client
# aws s3 ls --profile client --region eu-central-1
ROLE_ARN=$1
OUTPUT_PROFILE=$2
echo "Assuming role $ROLE_ARN"
sts=$(aws sts assume-role \
  --role-arn "$ROLE_ARN" \
  --role-session-name "$OUTPUT_PROFILE" \
  --query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken]' \
  --output text)
echo "Converting sts to array"
sts=($sts)
echo "AWS_ACCESS_KEY_ID is ${sts[0]}"
aws configure set aws_access_key_id ${sts[0]} --profile $OUTPUT_PROFILE
aws configure set aws_secret_access_key ${sts[1]} --profile $OUTPUT_PROFILE
aws configure set aws_session_token ${sts[2]} --profile $OUTPUT_PROFILE
echo "credentials stored in the profile named $OUTPUT_PROFILE"

How to use the assume role script

You run the assume role script with 2 arguments. First, you insert the role ARN of the target AWS account that you want to assume e.g.

arn:aws:iam::012345678910:role/crossaccount-tst-role

The second argument is how you want to name the AWS profile that you’re creating e.g. test-account.

./assume_role.sh arn:aws:iam::012345678910:role/crossaccount-tst-role test-account

Once the AWS profile is created with the STS credentials, we can run our actions on the target AWS account to run S3 commands for example:

aws s3 ls --profile test-account --region eu-central-1

We can also write SSM parameters to the target test account:

aws ssm put-parameter --name Environment --value Test --type "String" --overwrite --profile test-acount --region eu-central-1

Conclusion

Now you’ve set up a reusable assume role script by finishing the following steps:

  • Created an IAM role on the target AWS Account
  • Created an IAM role on the source AWS Account

You can now re-use this script in multiple CI/CD pipelines and grant cross-account access to your AWS resources.

Note: If you want to have access to different AWS resources, then make sure to update the policies that are attached to the IAM role on the target account.



Danny Steenman

A Senior AWS Cloud Engineer with over 9 years of experience migrating workloads from on-premises to AWS Cloud.

I have helped companies of all sizes shape their cloud adoption strategies, optimizing operational efficiency, reducing costs, and improving organizational agility.

Connect with me today to discuss your cloud aspirations, and let’s work together to transform your business by leveraging the power of AWS Cloud.

I need help with..
stacked cubes
Improving or managing my CDK App.Maximize the potential of your AWS CDK app by leveraging the expertise of a seasoned CDK professional.
Reducing AWS Costs.We can start by doing a thorough assessment of your current AWS infrastructure, identifying areas with potential for cost reduction and efficiency improvement.
Verifying if my infrastructure is reliable and efficient.We’ve created a comprehensive AWS Operations Checklist that you can utilize to quickly verify if your AWS Resources are set up reliably and efficiently.