I have 2 accounts:
- Account A (Master/Management account)
- Account B (Member account)
I deployed a Lambda function in Account B(Member account) that lists all the accounts in the organization. Below is the Lambda function code:
import boto3
import json
org_client = boto3.client('organizations')
org_id='o-ib1qmgzn48'
def lambda_handler(event, context):
account_list = []
def list_aws_accounts_for_ou(ou_id):
# add accounts in the current/root OU
try:
lafp_paginator = org_client.get_paginator('list_accounts_for_parent')
lafp_page_iterator = lafp_paginator.paginate(ParentId=org_id)
for page in lafp_page_iterator:
for acct in page['Accounts']:
account_list.append(acct)
except org_client.exceptions.ClientError as error:
print(f'Error: {error}')
# add accounts in child ous
try:
lc_paginator = org_client.get_paginator('list_children')
ou_page_iterator = lc_paginator.paginate(
ParentId=org_id,
ChildType='ORGANIZATIONAL_UNIT'
)
for page in ou_page_iterator:
for child in page['Children']:
print(f"Adding accounts from child OU {child['Id']}")
account_list = list_aws_accounts_for_ou(child['Id'])
except org_client.exceptions.ClientError as error:
print(f'Error: {error}')
print(f"Found {len(account_list)} accounts in Oraganization {org_id}")
return json.loads(json.dumps(account_list, default=str))
This Lambda function has a role(GetAccountsListLambdaRole) with the below permissions: Basic Lambda execution role An inline policy that assumes a role in Account A(Management/Master account)
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::Account A:role/OrganizationsReadAssumeRole"
}
}
The 'OrganizationsReadAssumeRole' in Account A has the following permissions and trust policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"organizations:ListAccounts",
"organizations:ListAccountsForParent",
"organizations:ListChildren"
],
"Resource": "*"
}
]
}
The trust policy is:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::Account B:role/GetAccountsListLambdaRole"
},
"Action": "sts:AssumeRole",
"Condition": {}
}
]
}
When I run the Lambda function, I'm getting the below errors:
Error: An error occurred (AccessDeniedException) when calling the ListAccountsForParent operation: You don't have permissions to access this resource.
Error: An error occurred (AccessDeniedException) when calling the ListChildren operation: You don't have permissions to access this resource.
I have a couple of questions here:
- Whatever I'm trying - getting an account list from a member account; is it possible? If yes, how can I resolve the above errors and achieve this?
Please help.
CodePudding user response:
You need to actually assume the OrganizationsReadAssumeRole
role in the lambda. This blog has an example:
sts_connection = boto3.client('sts')
acct_a = sts_connection.assume_role(
RoleArn="arn:aws:iam::222222222222:role/OrganizationsReadAssumeRole",
RoleSessionName="cross_acct_lambda"
)
ACCESS_KEY = acct_a['Credentials']['AccessKeyId']
SECRET_KEY = acct_a['Credentials']['SecretAccessKey']
SESSION_TOKEN = acct_a['Credentials']['SessionToken']
# create service client using the assumed role credentials, e.g. S3
org_client = boto3.client(
'organizations',
aws_access_key_id=ACCESS_KEY,
aws_secret_access_key=SECRET_KEY,
aws_session_token=SESSION_TOKEN,
)
... # rest of your code
Replace 222222222222
with the AWS account ID of the cross-account role that your function is assuming.