Clone AWS IAM Roles Across Environments/Accounts Using AWS CLI Automation

DEEPAK M SDEEPAK M S
6 min read

The Challenge: Scaling AWS IAM Role Across Multiple Environment

Picture this: you’ve just finished setting up your AWS infrastructure for development, complete with perfectly configured IAM roles for secure resource access. Everything works beautifully. Now comes the inevitable next step — replicating this setup for your UAT (User Acceptance Testing) environment.

Sound familiar? This is a common scenario that many AWS engineers face when managing multi-environment deployments.

Here’s what I was dealing with:

  • Multiple IAM roles (5+) configured for my application’s dev environment

  • Each role using role-based authentication for AWS resource access

  • Need to duplicate these roles for UAT with minimal changes

  • The only difference: resource ARNs pointing to UAT-specific resources

  • Both environments residing in the same AWS account but different VPCs

The manual approach? Copy-paste each role configuration, update ARNs, rename roles, attach policies… rinse and repeat. Not only time-consuming but also error-prone.

The smart approach? Automate the entire process using AWS CLI.

In this guide, I’ll walk you through a battle-tested CLI method that automates IAM role cloning across environments. Whether you’re moving roles between VPCs in the same account or even across different AWS accounts, this approach scales beautifully and saves hours of manual work.

Prerequisites: Setting Up Your AWS CLI Environment

Before we dive into the automation magic, let’s ensure your local environment is properly configured. Don’t worry — this is a one-time setup that will serve you well beyond this tutorial.

Step 1: Install AWS CLI v2

For this guide, I’m using Ubuntu, but the process is similar across Linux distributions. AWS provides comprehensive installation instructions in their official documentation:

aws documention

Step 2: Configure Your AWS Credentials

Once installed, open your terminal and run:

aws configure

This interactive command will prompt you for:

  • Access Key ID — Your AWS programmatic access key

  • Secret Access Key — The corresponding secret

  • Default Region — Your preferred AWS region (e.g., us-east-1)

  • Output Format — Recommended: json for better script compatibility

Pro Tip: Managing Multiple AWS Accounts

Here’s where things get interesting — and this is a game-changer for developers juggling multiple environments or clients. AWS CLI supports named profiles, allowing you to seamlessly switch between different AWS accounts.

# Configure your personal AWS account
aws configure --profile personal

# Configure your work/company account
aws configure --profile work

# Use commands with specific profiles
aws s3 ls --profile personal    # Lists S3 buckets from personal account
aws s3 ls --profile work        # Lists S3 buckets from work account

This approach eliminates the constant reconfiguration headache and reduces the risk of accidentally running commands against the wrong account — trust me, we’ve all been there!

For This Tutorial

To keep things focused and straightforward, I’ll demonstrate the role migration process using a single AWS account. However, the same principles and scripts work seamlessly across multiple accounts when using profiles.

Implementation: Building the IAM Role Cloning Solution

Now for the exciting part — let’s build our automated role cloning system. I’ll break this down into digestible steps, explaining the logic behind each component.

Step 1: Creating the Core Clone Function

The heart of our solution is a bash function that handles the heavy lifting. This function will:

  • Extract trust relationships from the source role

  • Clone all attached managed and inline policies

  • Apply intelligent naming conventions

  • Handle error scenarios gracefully

Here’s the complete clone_role() function:

clone_role() {
  local original_role=$1
  local new_role=$(echo $orginal_role | sed 's/^dev_/test_/')

  echo "Cloning $original_role to $new_role"

  echo "  Getting trust relationship"

  # update this with --profile argument for fetch it from other account
  aws iam get-role --role-name $original_role\
     --query 'Role.AssumeRolePolicyDocument'\
     --ouput json > /tmp/trust-policy-$new_role.json

  if [$? -ne 0]; then 
      echo "  ERROR: Failed to get trust policy for $original_role"
  fi

  # create new role
  echo "  Creating new role $new_role"
  aws iam create-role \
    --role-name $new_role \
    --assume-role-policy-document file:///tmp/trust-policy-$new_role.json \
    --description "Cloned from $original_role"

if [$? -ne 0]; then 
      echo "  ERROR: Failed to create role $new_role"
  fi

# get and attach managed policies
echo "  Getting Mangaed policies attached $original_role:"
managed_policies=$(aws iam list-attached-role-policies --role-name $original_role --query 'AttachedPolicies[].PolicyArn' --ouput text)

if [! -z "$managed_policies"]; then
  for policy_arn in $managed_policies; do
    echo "  Attaching managed Policy: $policy_arn"
    aws iam attach-role-policy --role-name $new_role --policy-arn $policy-arn
  done
fi

# get and attach inline policies
echo "  Getting inline policies..."
inline_policies=$(aws iam list-role-policies --role-name $original_role --query 'PolicyNames' --output text)
if [ ! -z "$inline_policies" ]; then
   for policy_name in $inline_policies; do
     echo "    Copying inline policy: $policy_name"
     # Get policy document
     aws iam get-role-policy \
        --role-name $original_role \
        --policy-name $policy_name \
        --query 'PolicyDocument' \
        --output json > /tmp/inline-policy-$policy_name.json

     new_policy_name = $(echo $policy_name | sed 's/dev/test/g')


     aws iam put-role-policy \
        --role-name $new_role \
        --policy_name $new_policy_name \
        --policy-document file:///tmp/inline-policy-$policy_name.json
   done

fi

# copy tags (optional)
echo "  Copying tags..."
tags=$(aws iam list-role-tags --role-name $original_role --query 'Tags' --output 
if [ "$tags" != "[]" ]; then
     # Update Environment tag from dev to test
     updated_tags=$(echo $tags | jq 'map(if .Key == "Environment" then .Value = "test" else . end)')
     echo $updated_tags > /tmp/tags-$new_role.json

     aws iam tag-role --role-name $new_role --tags file:///tmp/tags-$new_role.json
fi
echo "  ✅ Successfully cloned $original_role to $new_role"
echo ""
}

Step 2: Orchestrating the Complete Solution

Now let’s build the main script that ties everything together:

#!/bin/bash


# Original role names
ORIGINAL_ROLES=(
    # put your roles here
)

echo "Starting IAM role cloning process..."
echo "========================================"

aws sts get-caller-identity > /dev/null 2>&1
if [ $? -ne 0 ]; then
    echo "ERROR: AWS CLI not configured or no permissions"
    exit 1
fi

for role in "${ORIGINAL_ROLES[@]}"; do
    clone_role $role
done

# Cleanup temporary files
echo "Cleaning up temporary files..."
rm -f /tmp/trust-policy-*.json
rm -f /tmp/inline-policy-*.json
rm -f /tmp/tags-*.json

echo "========================================"
echo "✅ Role cloning completed!"
echo ""
echo "New roles created:"
for role in "${ORIGINAL_ROLES[@]}"; do
    new_role=$(echo $role | sed 's/^dev_/test_/')
    echo "  - $new_role"
done

Key Features of This Implementation:

  1. Intelligent Naming: Automatically converts dev_ prefixes to test_

  2. Comprehensive Cloning: Copies trust policies, managed policies, inline policies, and tags

  3. Error Handling: Gracefully handles failures and provides clear error messages

  4. Environment-Aware: Updates environment tags appropriately

  5. Clean Operations: Automatically removes temporary files

Pro Tips for Customization:

  • Cross-Account Migration: Add --profile flags to AWS commands for different accounts

  • Custom Naming: Modify the sed pattern for your naming conventions

  • Selective Cloning: Add conditions to skip certain policies or tags

Ready to Use?

The complete, production-ready script is available in my GitHub repository:

Github

Feel free to clone, customize, and adapt it to your specific requirements. The script is configured for dev-to-test migration but can be easily modified for any environment combination.

Thank you for taking the time to read through this guide! I hope this automation solution saves you as much time and effort as it has saved me. There’s nothing quite like watching a script handle tedious manual work while you focus on more strategic tasks.

If you found this helpful, please follow me for more AWS automation tips, infrastructure-as-code tutorials, and DevOps best practices. I regularly share battle-tested solutions from real-world scenarios.

Happy coding! 🚀

0
Subscribe to my newsletter

Read articles from DEEPAK M S directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

DEEPAK M S
DEEPAK M S