AWS Lambda : Cross account Policy for Lambda function S3 to S3 copy

we are trying to implement the lambda function which will copy the object from one S3 to another S3 bucket in cross account based on the source S3 bucket events. Currently we are able to copy the file between source and target within same SAG . But when we tried to implement the same logic with cross account , getting the CopyObject operation: Access Denied issue . I have given following bucket policy. Can you please help me to get the correct IAM and bucket policy to resolve this issue .

{
    "Version": "2012-10-17",
    "Id": "Policy1603404813917",
    "Statement": [
        {
            "Sid": "Stmt1603404812651",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::6888889898:role/Staff"
            },
            "Action": [
                "s3:GetObject",
                "s3:GetObjectAcl",
                "s3:ListBucket",
                "s3:PutObject",
                "s3:PutObjectAcl"
            ],
            "Resource": [
                "arn:aws:s3:::source-bucktet-testing-lambda/*",
                "arn:aws:s3:::source-bucktet-testing-lambda"
            ]
        }
    ]
}

based on the https://www.lixu.ca/2016/09/aws-lambda-and-s3-how-to-do-cross_83.html link , Yes, we can implement the same logic with help of access ID and access secret keys for source and dest. But am trying to implement same logic instead of access ID and access secret keys for source and dest, granting access for both source and target buckets with appropriate policy and make it work as like same account .

Upvotes: 4

Views: 9049

Answers (2)

John Rotenstein
John Rotenstein

Reputation: 270224

To reproduce your situation, I did the following:

  • In Account-A:
    • Created an Amazon S3 bucket (Bucket-A)
    • Created an IAM Role (Role-A)
    • Created an AWS Lambda function (Lambda-A) and assigned Role-A to the function
    • Configured an Amazon S3 Event on Bucket-A to trigger Lambda-A for "All object create events"
  • In Account-B:
    • Created an Amazon S3 bucket (Bucket-B) with a bucket policy (see below)

IAM Role

Role-A has the AWSLambdaBasicExecutionRole managed policy, and also this Inline Policy that assigns the Lambda function permission to read from Bucket-A and write to Bucket-B:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::bucket-a/*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:PutObjectAcl"
            ],
            "Resource": "arn:aws:s3:::bucket-b/*"
        }
    ]
}

Bucket Policy on destination bucket

The Bucket Policy on Bucket-B permits access from the Role-A IAM Policy:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::ACCOUNT-A:role/role-a"
            },
            "Action": [
                "s3:PutObject",
                "s3:PutObjectAcl"
            ],
            "Resource": "arn:aws:s3:::bucket-b/*"
        }
    ]
}

Lambda Function

Lambda-A is triggered when an object is created in Bucket-A, and copies it to Bucket-B:

import boto3
import urllib

TARGET_BUCKET = 'bucket-b'

def lambda_handler(event, context):
    
    # Get incoming bucket and key
    source_bucket = event['Records'][0]['s3']['bucket']['name']
    source_key = urllib.parse.unquote_plus(event['Records'][0]['s3']['object']['key'])

    # Copy object to different bucket
    s3_resource = boto3.resource('s3')
    copy_source = {
        'Bucket': source_bucket,
        'Key': source_key
    }
    target_key = source_key # Change if desired

    s3_resource.Bucket(TARGET_BUCKET).Object(target_key).copy(copy_source, ExtraArgs={'ACL': 'bucket-owner-full-control'})

I grant ACL=bucket-owner-full-control because copying objects to buckets owned by different accounts can sometimes cause the objects to still be 'owned' by the original account. Using this ACL grants ownership to the account that owns the destination bucket.

Testing

I uploaded a file to Bucket-A in Account-A.

The file was correctly copied to Bucket-B in Account-B.

Comments

The solution does NOT require:

  • A bucket policy on Bucket-A, since Role-A grants the necessary permissions
  • Turning off S3 Block Public Access, since the permissions assigned do not grant 'public' access

Upvotes: 13

Nishit
Nishit

Reputation: 1354

Assuming the following

  1. Above mentioned policy is for the source bucket
  2. 6888889898 is the Destination AWS account
  3. Lambda for copying the file is located in the destination AWS account and has Staff role attached to it.

Even after setting all these correctly, the copy operation may fail. This is because the Policy allows you to get/put s3 objects, but not the tags associated with those s3 objects.

You will need to ALLOW the following actions as well "s3:GetObjectTagging" and "s3:PutObjectTagging"

Upvotes: 0

Related Questions