Sitemap
Stackademic

Stackademic is a learning hub for programmers, devs, coders, and engineers. Our goal is to democratize free coding education for the world.

AWS: Cross Account Resource Access

5 min readApr 2, 2024

--

There are basically two ways to access an AWS resource that is an different account.

  • Attach a resource policy directly to the resource
  • Use a role as a proxy

However, not all resources support resource-based policies. You can find that out in AWS services that work with IAM and look for the services that have Yes in the Resource Based column.

Here are couple example resources that do support resource-based policies.

  • S3 buckets
  • Simple Notification Service (SNS) topics
  • Simple Queue Service (SQS) queues

In this article, we will be taking a look on how to use an IAM role as a proxy to access resources in another account.

Specifically, we will be taking a look at a super simple example where we will have a Lambda fucntion in Account 1 Accessing S3 Bucket in Account 2.

Create Lambda in Account 1

We will first create a Lambda function in Account 1.

Head to Lambda Console > Functions.

Choose Create function.

Press enter or click to view image in full size

Choose Author from scratch and choose Python 3.12 as the Runtime.

Press enter or click to view image in full size

Choose Create a new role.

Press enter or click to view image in full size

Choose Create function.

After creation, head to Configuration Tab.

Press enter or click to view image in full size

Click on the super link on the Role name and memo down Role ARN. We will be using this to configure resource permissions in Account 2.

Press enter or click to view image in full size

We will be coming back to make more configurations and edit the code part in a short while.

Cross Account Access Role in Account 2

This will be the IAM Role in Account 2 that

  • Will be assumed by the Lambda function above in Account 1, and
  • Has Full S3 access within Account 2.

Head to IAM Console > Role.

Choose Create role.

Press enter or click to view image in full size

Choose AWS account as Trusted entity type.

Press enter or click to view image in full size

Select Another AWS account and enter your Account ID for Account 1.

Press enter or click to view image in full size

Choose Next.

Under Add permissions, Search for AmazonS3FullAcess and check it.

Press enter or click to view image in full size

Choose Next.

Press enter or click to view image in full size

Give the role a name and choose Create role.

After creation, choose Trust relationships tab.

Press enter or click to view image in full size

Here is what you currently have.

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

We want to change the Principle ARN to the role ARN of our Lambda execution role in Account 1. You will always want to give the least permission needed to ensure security.

Get Itsuki’s stories in your inbox

Join Medium for free to get updates from this writer.

Choose Edit trust policy and change it to the ARN you have noted down.

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "lambda_role_arn"
},
"Action": "sts:AssumeRole",
"Condition": {}
}
]
}

Choose Update policy.

Under Summary, find the Role Arn and memo it somewhere.

Press enter or click to view image in full size

Configure Lambda

Now let’s head back to Account 1 to configure our Lambda function.

Add Environment Variable

First of all, let’s add our CrossAccountAccessRole ARN from Account 2 as an environment variable.

Choose Configuration > Environment variables.

Choose Edit.

Press enter or click to view image in full size

For Key, enter CROSS_ACCOUNT_ROLE_ARN. And for Value, enter the ARN you noted down above.

Press enter or click to view image in full size

Choose Save.

Add Assume Role Policy

To have our Lambda function being able to assume the CrossAccountAccessRole in Account 2, we will have to add the policy to allow this action.

Choose Configuration > Permissions and click on the super link on the Role name.

Press enter or click to view image in full size

Choose Add permissions > Create inline policy.

Press enter or click to view image in full size

Choose STS.

For Actions allowed, choose AssumeRole.

Press enter or click to view image in full size

Choose Specific for Resources and Click on Add ARNS.

Press enter or click to view image in full size

Copy and paste the Account 2 CrossAccountAccessRole ARN into Resource ARN. This will automatically fill in the above two fields for you.

Choose Add ARNs.

Press enter or click to view image in full size

Enter a Policy name and Choose Create policy.

Configure Lambda to Assume Account2 CrossAccountAccessRole

To get a set of temporary security credentials that we can use to access Account 2 S3 resources, we will be using STS.Client.assume_role by passing in our Account 2 CrossAccountAccessRole ARN to it.

sts = boto3.client('sts')
response = sts.assume_role(
RoleArn=os.getenv("CROSS_ACCOUNT_ROLE_ARN"),
RoleSessionName='lambda-s3-access-session',
DurationSeconds=900 # how many seconds these credentials will work
)

In order to configure our s3 client to access S3 resources in another account instead of the default (current) one, we will need to manually set the aws_access_key_id, aws_secret_access_key, and aws_session_token that can be retrieved from the response above like following.

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

Now, we can simply list our buckets by using

response = s3.list_buckets()

Just putting everything together, here will be our lambda_handler function.

import json
import boto3
import os

sts = boto3.client('sts')


def lambda_handler(event, context):

response = sts.assume_role(
RoleArn=os.getenv("CROSS_ACCOUNT_ROLE_ARN"),
RoleSessionName='lambda-s3-access-session',
DurationSeconds=900 # how many seconds these credentials will work
)

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

response = s3.list_buckets()

print(response)

return {
'statusCode': 200,
'body': json.dumps('Hello from Lambda!')
}

We can test it under Test tab to confirm the success and we are indeed getting a list of our S3 buckets in Account 2.

Press enter or click to view image in full size

That’s it!

Thank you for reading!

Have a nice day!

Stackademic 🎓

Thank you for reading until the end. Before you go:

--

--

Stackademic
Stackademic

Published in Stackademic

Stackademic is a learning hub for programmers, devs, coders, and engineers. Our goal is to democratize free coding education for the world.