Skip to content

Lambda: Incorrect account used for S3 event source mapping #21628

@Timidger

Description

@Timidger

Describe the bug

When adding an S3 bucket as an event source to a lambda the account for the bucket is sourced from the stack not from the bucket configuration.

Expected Behavior

We have a stack intending to deploy, amongst other things, a Lambda to account "A"

We reference a Bucket (which lives in account "B") using fromBucketAttributes in the same stack and specified account "B" as the account attribute (see reproduction steps). When hooking it up to the Lambda using addEventSource we expect that it will generate IAM configuration specifying account "B" as part of the conditional grant.

Expected output from CDK:

├───┼───────────────────────────────────┼────────┼───────────────────────┼───────────────────────────────────┼───────────────────────────────────┤
│ + │ ${my-stack                        │ Allow  │ lambda:InvokeFunction │ Service:s3.amazonaws.com          │ "ArnLike": {                      │
│   │                                   │        │                       │                                   │   "AWS:SourceArn": "arn:aws-cn:s3 │
│   │                                   │        │                       │                                   │ :::the-bucket"                    │
│   │                                   │        │                       │                                   │ },                                │
│   │                                   │        │                       │                                   │ "StringEquals": {                 │
│   │                                   │        │                       │                                   │   "AWS:SourceAccount": "<ACCT B>" │
│   │                                   │        │                       │                                   │                                   │
│   │                                   │        │                       │                                   │ }                                 │
└───┴───────────────────────────────────┴────────┴───────────────────────┴───────────────────────────────────┴───────────────────────────────────┘

Current Behavior

Account "A" is defined as the "source account" which is incorrect. The Bucket lives in account "B" and was only referenced in the stack whose resources get deployed to "A".

Actual output from CDK:

├───┼───────────────────────────────────┼────────┼───────────────────────┼───────────────────────────────────┼───────────────────────────────────┤
│ + │ ${my-stack                        │ Allow  │ lambda:InvokeFunction │ Service:s3.amazonaws.com          │ "ArnLike": {                      │
│   │                                   │        │                       │                                   │   "AWS:SourceArn": "arn:aws-cn:s3 │
│   │                                   │        │                       │                                   │ :::the-bucket"                    │
│   │                                   │        │                       │                                   │ },                                │
│   │                                   │        │                       │                                   │ "StringEquals": {                 │
│   │                                   │        │                       │                                   │   "AWS:SourceAccount": "<ACCT A>" │
│   │                                   │        │                       │                                   │                                   │
│   │                                   │        │                       │                                   │ }                                 │
└───┴───────────────────────────────────┴────────┴───────────────────────┴───────────────────────────────────┴───────────────────────────────────┘

Reproduction Steps

import { DeploymentStack, DeploymentStackProps } from "@amzn/pipelines";
import { Code, Function, Runtime } from 'aws-cdk-lib/aws-lambda';
import { S3EventSource } from "aws-cdk-lib/aws-lambda-event-sources";
import { Bucket, EventType } from "aws-cdk-lib/aws-s3";
import { Construct } from "constructs";

export class BuggyStack extends DeploymentStack {
    constructor(scope: Construct, id: string, props: DeploymentStackProps) {
        super(scope, id, props);
        let accountB = '123456789';

        const foreignBucket =
            Bucket.fromBucketAttributes(this, 'ImportedBucket', {
                bucketArn: 'arn:aws:s3:::some-bucket-not-in-this-account',
                // The account the bucket really lives in
                account: accountB
            });

        let myLambda = new Function(this, 'my-function', {
            runtime: Runtime.PYTHON_3_9,
            code: Code.fromInline('print("hello world")'),
            handler: 'whatever'
        });

        // This will generate the incorrect IAM bindings
        myLambda.addEventSource(new S3EventSource(foreignBucket as Bucket,
            { events: [ EventType.OBJECT_CREATED ] }));
    }
}

Possible Solution

To me, the most correct solution involves sourcing the bucket account from the bucket configuration itself. Since it's possible to specify the bucket account ID it's surprising when that isn't used when generating the IAM permissions.

I found a very bad workaround in the meantime in case anyone else is running into this:

type Writeable<T> = { -readonly [ P in keyof T ]: T[ P ] };
let stack: Writeable<Stack> = Stack.of(myBucket);
let accountA = stack.account;
stack.account = accountB;
myLambda.addEventSource(new S3EventSource(myBucket, { events: myEvents }));
stack.account = accountA;

Additional Information/Context

No response

CDK CLI Version

2.29.0 (build 47d7ec4)

Framework Version

No response

Node.js Version

v14.19.3

OS

Amazon Linux 2

Language

Typescript

Language Version

No response

Other information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    @aws-cdk/aws-lambdaRelated to AWS LambdabugThis issue is a bug.effort/smallSmall work item – less than a day of effortp1

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions