noobie2023
noobie2023

Reputation: 783

Role-based cross-account S3 access

I have two aws accounts, A and B. Account A has a lambda function that needs access to a s3 bucket in Account B.

To simulate this case, I have the following settings:

The Account B (data source) has a role:

arn:aws:iam::${Account_B}:role/jeff-full-s3-access-role and is attached with AmazonS3FullAccess policy. This role has a trusted entity arn:aws:iam::${Account_A}:role/jeff-test-lambda-role

Meanwhile, arn:aws:iam::${Account_A}:role/jeff-test-lambda-role resides in Account A and it has a trusted entity lambda.amazonaws.com. And I've attached the following in-line policy with it:

{
    "Version": "2012-10-17",
    "Statement": {
        "Effect": "Allow",
        "Action": "sts:AssumeRole",
        "Resource": "arn:aws:iam::${Account_B}:role/jeff-full-s3-access-role"
    }
}

Now when I invoked the lambda function (python):

import json
from boto3 import client

def lambda_handler(event, context):
    conn = client('s3')  # again assumes boto.cfg setup, assume AWS S3
    for key in conn.list_objects(Bucket='Bucket_in_Account_B')['Contents']:
        print(key['Key'])

    return {}

But getting the following error:

{
  "errorMessage": "An error occurred (AccessDenied) when calling the ListObjects operation: Access Denied",
  "errorType": "ClientError",
  "stackTrace": [
    "  File \"/var/task/lambda_function.py\", line 6, in lambda_handler\n    for key in conn.list_objects(Bucket='Bucket_in_Account_B')['Contents']:\n",
    "  File \"/var/runtime/botocore/client.py\", line 386, in _api_call\n    return self._make_api_call(operation_name, kwargs)\n",
    "  File \"/var/runtime/botocore/client.py\", line 705, in _make_api_call\n    raise error_class(parsed_response, operation_name)\n"
  ]
}

Does anyone know the reason why this is not working? This post may work but it's a couple of years ago. I'm wondering if there's a way to achieve this without using Bucket Policy.

Thank you!

Upvotes: 0

Views: 921

Answers (1)

John Rotenstein
John Rotenstein

Reputation: 269091

The easiest way to meet your requirement is to add a Bucket Policy on the bucket in Account B that permits access from the IAM Role used by the AWS Lambda function in Account A. This avoids any requirement to assume roles.

As for your current code, it is failing because your program needs to call assume_role() to obtain credentials from Account B. It then needs to use those credentials to create a new boto3.client() object for use when accessing resources in Account B. For an example, see: boto - AWS: Boto3: AssumeRole example which includes role usage - Stack Overflow

Upvotes: 1

Related Questions