Skip to content
Linuxbeast
  • Home
  • Today in Tech
  • Who is Hiring?
  • About Me
  • Work With Me
  • Tools
    • DevOps Onboarding
    • AWS VPC Subnet Planner
    • Tag Network
    • Pag-IBIG Housing Loan Calculator
  • Contact
How to Set Up Cross-Account Access in AWS with AssumeRole

How to Set Up Cross-Account Access in AWS with AssumeRole

March 9, 2026May 15, 2024 by Linuxbeast
5 min read

When you manage multiple AWS accounts, you often need resources in one account to access services in another — deploying code, reading S3 buckets, or querying databases across accounts. Cross-account access in AWS with AssumeRole lets you do this without sharing credentials. You create a role in the target account, grant permission to assume it from the source account, and switch contexts using temporary credentials.

The examples here are run on WSL2 Ubuntu in Windows, but the AWS CLI commands work the same on any system.

How AssumeRole Works

The setup involves two accounts:

  • Account A (111111111111) — the account that needs access
  • Account B (222222222222) — the account that owns the resources

Account B creates an IAM role with a trust policy that says “Account A is allowed to assume this role.” Account A’s users or services then call sts:AssumeRole to get temporary credentials that work in Account B. These credentials expire automatically (default: 1 hour).

Prerequisites

  • AWS CLI v2 installed and configured
  • IAM admin access in both accounts (or enough permissions to create roles and policies)

Step 1: Create the Role in Account B

In Account B (the account with the resources), create an IAM role that Account A can assume.

Trust policy

Save this as trust-policy.json. It allows Account A’s root principal to assume the role:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::111111111111:root"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

Using the root principal means any IAM user or role in Account A can assume this role — but only if they also have an sts:AssumeRole permission on their side (Step 2). To restrict to a specific user or role, replace root with the full ARN (e.g., arn:aws:iam::111111111111:user/deployer).

Create the role

aws iam create-role \
  --role-name CrossAccountAccessRole \
  --assume-role-policy-document file://trust-policy.json \
  --profile account-b

Attach permissions

Attach the permissions that the role needs. For example, to grant read-only S3 access:

aws iam attach-role-policy \
  --role-name CrossAccountAccessRole \
  --policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess \
  --profile account-b

Use the least-privilege principle — only attach the permissions the role actually needs. You can use AWS managed policies or create a custom policy scoped to specific resources.

Step 2: Grant AssumeRole Permission in Account A

In Account A, the user or role that will assume the cross-account role needs permission to call sts:AssumeRole. Create a policy and attach it to the IAM user, group, or role:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "sts:AssumeRole",
            "Resource": "arn:aws:iam::222222222222:role/CrossAccountAccessRole"
        }
    ]
}

Save this as assume-role-policy.json and attach it:

aws iam put-user-policy \
  --user-name deployer \
  --policy-name AllowCrossAccountAccess \
  --policy-document file://assume-role-policy.json \
  --profile account-a

Only sts:AssumeRole is required here. You don’t need iam:PassRole or iam:ListRoles — those are for different use cases.

Step 3: Assume the Role

There are three ways to assume the role: an AWS CLI profile (recommended for regular use), a one-time CLI command, or boto3 in Python.

Option A: AWS CLI profile (recommended)

Add a profile to ~/.aws/config that automatically assumes the role when you use it:

[profile account-b-cross]
role_arn = arn:aws:iam::222222222222:role/CrossAccountAccessRole
source_profile = account-a

Now any AWS CLI command with --profile account-b-cross assumes the role automatically:

aws s3 ls --profile account-b-cross
  • role_arn — the role in Account B to assume
  • source_profile — your Account A credentials profile, used to authenticate the AssumeRole call

The CLI handles the sts:AssumeRole call, caches the temporary credentials, and refreshes them when they expire.

Option B: Manual CLI command with environment variables

For scripts or one-off access, call sts assume-role directly and export the temporary credentials:

OUT=$(aws sts assume-role \
  --role-arn "arn:aws:iam::222222222222:role/CrossAccountAccessRole" \
  --role-session-name "cross-account-session" \
  --profile account-a)

export AWS_ACCESS_KEY_ID=$(echo $OUT | jq -r '.Credentials.AccessKeyId')
export AWS_SECRET_ACCESS_KEY=$(echo $OUT | jq -r '.Credentials.SecretAccessKey')
export AWS_SESSION_TOKEN=$(echo $OUT | jq -r '.Credentials.SessionToken')
  • --role-session-name — a label for this session (shows up in CloudTrail logs)
  • Requires jq installed (sudo apt install -y jq)
  • These credentials expire after 1 hour by default

After exporting, any AWS CLI command in the same terminal session runs as Account B’s role:

aws s3 ls
aws sts get-caller-identity

To stop using the assumed role, unset the environment variables:

unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN

Option C: boto3 in Python

For Lambda functions or Python scripts that need cross-account access:

import boto3

sts_client = boto3.client('sts')
response = sts_client.assume_role(
    RoleArn='arn:aws:iam::222222222222:role/CrossAccountAccessRole',
    RoleSessionName='lambda-cross-account'
)

credentials = response['Credentials']
s3_client = boto3.client(
    's3',
    aws_access_key_id=credentials['AccessKeyId'],
    aws_secret_access_key=credentials['SecretAccessKey'],
    aws_session_token=credentials['SessionToken']
)

# Now use s3_client to interact with Account B's S3
buckets = s3_client.list_buckets()
print(buckets)

Adjusting Session Duration

By default, temporary credentials from AssumeRole expire after 1 hour. You can set a longer duration (up to 12 hours) when assuming the role:

aws sts assume-role \
  --role-arn "arn:aws:iam::222222222222:role/CrossAccountAccessRole" \
  --role-session-name "long-session" \
  --duration-seconds 3600 \
  --profile account-a

The role’s maximum session duration must also be updated to allow longer sessions. Set it when creating or updating the role:

aws iam update-role \
  --role-name CrossAccountAccessRole \
  --max-session-duration 43200 \
  --profile account-b

Valid values: 3600 (1 hour) to 43200 (12 hours).

Verifying the Setup

After assuming the role, confirm which identity you’re using:

aws sts get-caller-identity --profile account-b-cross

The output should show Account B’s account ID and the assumed role ARN:

{
    "UserId": "AROAEXAMPLEID:cross-account-session",
    "Account": "222222222222",
    "Arn": "arn:aws:sts::222222222222:assumed-role/CrossAccountAccessRole/cross-account-session"
}

Troubleshooting

Error Cause
AccessDenied when calling AssumeRole Account A’s user is missing the sts:AssumeRole permission, or Account B’s trust policy doesn’t include Account A
Not authorized to perform: iam:PassRole You’re trying to pass the role to a service (like Lambda or ECS), which requires a separate iam:PassRole permission — this is different from AssumeRole
Credentials expire too quickly Increase --duration-seconds in the assume-role call and update the role’s --max-session-duration
Wrong account in get-caller-identity Environment variables from a previous session may be overriding your profile. Run unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN

Conclusion

The setup comes down to: create a role with a trust policy in Account B, grant sts:AssumeRole in Account A, and use the CLI profile method to switch contexts automatically. For regular use, the ~/.aws/config profile approach is the cleanest — no scripts, no environment variables.

For specific cross-account use cases, see How to Copy S3 Bucket Objects Across AWS Accounts or How to Access AWS Secrets Manager from Another Account.

Categories AWS Tags AssumeRole, AWS CLI, Cross-Account, IAM, Security, STS
How to Connect Visual Studio Code with WSL 2 for Linux Ubuntu
How to Add Swap Space on EC2 Ubuntu 22.04
← PreviousHow to Connect Visual Studio Code with WSL 2 for Linux UbuntuNext →How to Add Swap Space on EC2 Ubuntu 22.04

Related Articles

How to Add and Delete Users on Ubuntu (EC2, WSL, or Any Server)
AWS

How to Add and Delete Users on Ubuntu (EC2, WSL, or Any Server)

How to Avoid Unexpected AWS Lambda Costs
AWS

How to Avoid Unexpected AWS Lambda Costs

How to Install PHP 8.3 on an EC2 Ubuntu 22.04 LTS Instance
AWS

How to Install PHP 8.3 on an EC2 Ubuntu 22.04 LTS Instance

© 2026 Linuxbeast • Built with GeneratePress
Manage Consent
To provide the best experiences, we use technologies like cookies to store and/or access device information. Consenting to these technologies will allow us to process data such as browsing behavior or unique IDs on this site. Not consenting or withdrawing consent, may adversely affect certain features and functions.
Functional Always active
The technical storage or access is strictly necessary for the legitimate purpose of enabling the use of a specific service explicitly requested by the subscriber or user, or for the sole purpose of carrying out the transmission of a communication over an electronic communications network.
Preferences
The technical storage or access is necessary for the legitimate purpose of storing preferences that are not requested by the subscriber or user.
Statistics
The technical storage or access that is used exclusively for statistical purposes. The technical storage or access that is used exclusively for anonymous statistical purposes. Without a subpoena, voluntary compliance on the part of your Internet Service Provider, or additional records from a third party, information stored or retrieved for this purpose alone cannot usually be used to identify you.
Marketing
The technical storage or access is required to create user profiles to send advertising, or to track the user on a website or across several websites for similar marketing purposes.
  • Manage options
  • Manage services
  • Manage {vendor_count} vendors
  • Read more about these purposes
View preferences
  • {title}
  • {title}
  • {title}