Deploy Lambda and Configure Event Mapping with AWS CDK#

Keywords: Amazon, AWS, Lambda, CDK, Event

Overview#

This document provides a comprehensive list of sample AWS CDK code in Python to deploy a Lambda function and configure event mapping for various AWS services.

# create virtualenv
virtualenv -p python3.10 .venv

# activate virtualenv
source .venv/bin/activate

# install dependencies
pip install -r requirements.txt

# deploy
python cdk_deploy.py

# delete
python cdk_delete.py

S3 put#

s3-put.json
 1{
 2    "Records": [
 3        {
 4            "eventVersion": "2.0",
 5            "eventSource": "aws:s3",
 6            "awsRegion": "us-east-1",
 7            "eventTime": "1970-01-01T00:00:00.000Z",
 8            "eventName": "ObjectCreated:Put",
 9            "userIdentity": {
10                "principalId": "EXAMPLE"
11            },
12            "requestParameters": {
13                "sourceIPAddress": "127.0.0.1"
14            },
15            "responseElements": {
16                "x-amz-request-id": "EXAMPLE123456789",
17                "x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH"
18            },
19            "s3": {
20                "s3SchemaVersion": "1.0",
21                "configurationId": "testConfigRule",
22                "bucket": {
23                    "name": "example-bucket",
24                    "ownerIdentity": {
25                        "principalId": "EXAMPLE"
26                    },
27                    "arn": "arn:aws:s3:::example-bucket"
28                },
29                "object": {
30                    "key": "test%2Fkey",
31                    "size": 1024,
32                    "eTag": "0123456789abcdef0123456789abcdef",
33                    "sequencer": "0A1B2C3D4E5F678901"
34                }
35            }
36        }
37    ]
38}

S3 delete#

s3-delete.json
 1{
 2    "Records": [
 3        {
 4            "eventVersion": "2.0",
 5            "eventSource": "aws:s3",
 6            "awsRegion": "us-east-1",
 7            "eventTime": "1970-01-01T00:00:00.000Z",
 8            "eventName": "ObjectRemoved:Delete",
 9            "userIdentity": {
10                "principalId": "EXAMPLE"
11            },
12            "requestParameters": {
13                "sourceIPAddress": "127.0.0.1"
14            },
15            "responseElements": {
16                "x-amz-request-id": "EXAMPLE123456789",
17                "x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH"
18            },
19            "s3": {
20                "s3SchemaVersion": "1.0",
21                "configurationId": "testConfigRule",
22                "bucket": {
23                    "name": "example-bucket",
24                    "ownerIdentity": {
25                        "principalId": "EXAMPLE"
26                    },
27                    "arn": "arn:aws:s3:::example-bucket"
28                },
29                "object": {
30                    "key": "test%2Fkey",
31                    "sequencer": "0A1B2C3D4E5F678901"
32                }
33            }
34        }
35    ]
36}

SNS Notification#

sns-notification.json
 1{
 2    "Records": [
 3        {
 4            "EventSource": "aws:sns",
 5            "EventVersion": "1.0",
 6            "EventSubscriptionArn": "arn:aws:sns:us-east-1:{{{accountId}}}:ExampleTopic",
 7            "Sns": {
 8                "Type": "Notification",
 9                "MessageId": "95df01b4-ee98-5cb9-9903-4c221d41eb5e",
10                "TopicArn": "arn:aws:sns:us-east-1:123456789012:ExampleTopic",
11                "Subject": "example subject",
12                "Message": "example message",
13                "Timestamp": "1970-01-01T00:00:00.000Z",
14                "SignatureVersion": "1",
15                "Signature": "EXAMPLE",
16                "SigningCertUrl": "EXAMPLE",
17                "UnsubscribeUrl": "EXAMPLE",
18                "MessageAttributes": {
19                    "Test": {
20                        "Type": "String",
21                        "Value": "TestString"
22                    },
23                    "TestBinary": {
24                        "Type": "Binary",
25                        "Value": "TestBinary"
26                    }
27                }
28            }
29        }
30    ]
31}
app.py
 1# -*- coding: utf-8 -*-
 2
 3from pathlib import Path
 4
 5from boto_session_manager import BotoSesManager
 6
 7import aws_cdk as cdk
 8import aws_cdk.aws_iam as iam
 9import aws_cdk.aws_sns as sns
10import aws_cdk.aws_sns_subscriptions as sns_subscription
11import aws_cdk.aws_lambda as lambda_
12from constructs import Construct
13
14
15class Stack(cdk.Stack):
16    def __init__(
17        self,
18        scope: Construct,
19        id: str,
20        project_name: str,
21        **kwargs,
22    ) -> None:
23        project_name_slug = project_name.replace("_", "-")
24        super().__init__(scope, id=id, stack_name=project_name_slug, **kwargs)
25
26        self.iam_role_for_lbd = iam.Role(
27            self,
28            "IamRoleForLambda",
29            assumed_by=iam.ServicePrincipal("lambda.amazonaws.com"),
30            role_name=f"{project_name}-{cdk.Aws.REGION}-lambda-role",
31            managed_policies=[
32                iam.ManagedPolicy.from_aws_managed_policy_name("PowerUserAccess")
33            ],
34        )
35
36        # SNS is declared in the same stack
37        self.sns_topic_name = f"{project_name}-topic"
38        self.sns_topic = sns.Topic(
39            self,
40            "SNSTopic",
41            topic_name=self.sns_topic_name,
42        )
43
44        self.lbd_func_1 = lambda_.Function(
45            self,
46            "LambdaFunction1",
47            function_name=f"{project_name}-1",
48            code=lambda_.Code.from_asset(f"{dir_lambda_app}"),
49            handler=f"lambda_function.lambda_handler",
50            runtime=lambda_.Runtime.PYTHON_3_10,
51            memory_size=128,
52            timeout=cdk.Duration.seconds(3),
53            role=self.iam_role_for_lbd,
54        )
55
56        self.sns_topic.add_subscription(
57            sns_subscription.LambdaSubscription(self.lbd_func_1)
58        )
59
60        # SNS is declared in another stack
61        self.lbd_func_2 = lambda_.Function(
62            self,
63            "LambdaFunction2",
64            function_name=f"{project_name}-2",
65            code=lambda_.Code.from_asset(f"{dir_lambda_app}"),
66            handler=f"lambda_function.lambda_handler",
67            runtime=lambda_.Runtime.PYTHON_3_10,
68            memory_size=128,
69            timeout=cdk.Duration.seconds(3),
70            role=self.iam_role_for_lbd,
71        )
72
73        sns_topic = sns.Topic.from_topic_arn(
74            self,
75            "SNSTopicInterface",
76            topic_arn=f"arn:aws:sns:{cdk.Aws.REGION}:{cdk.Aws.ACCOUNT_ID}:{self.sns_topic_name}",
77        )
78        sns_topic.add_subscription(sns_subscription.LambdaSubscription(self.lbd_func_2))
79
80
81# ------------------------------------------------------------------------------
82# Config
83aws_profile = "bmt_app_dev_us_east_1"
84project_name = "lbd_cdk_event_demo-sns"
85# ------------------------------------------------------------------------------
86
87dir_workspace = Path(__file__).absolute().parent
88dir_lambda_app = dir_workspace.joinpath("lambda_app")
89bsm = BotoSesManager(profile_name=aws_profile)
90
91app = cdk.App()
92stack = Stack(app, "MyApp", project_name=project_name)
93
94if __name__ == "__main__":
95    app.synth()

SQS#

sqs.json
 1{
 2    "Records": [
 3        {
 4            "messageId": "19dd0b57-b21e-4ac1-bd88-01bbb068cb78",
 5            "receiptHandle": "MessageReceiptHandle",
 6            "body": "Hello from SQS!",
 7            "attributes": {
 8                "ApproximateReceiveCount": "1",
 9                "SentTimestamp": "1523232000000",
10                "SenderId": "123456789012",
11                "ApproximateFirstReceiveTimestamp": "1523232000001"
12            },
13            "messageAttributes": {},
14            "md5OfBody": "{{{md5_of_body}}}",
15            "eventSource": "aws:sqs",
16            "eventSourceARN": "arn:aws:sqs:us-east-1:123456789012:MyQueue",
17            "awsRegion": "us-east-1"
18        }
19    ]
20}
app.py
  1# -*- coding: utf-8 -*-
  2
  3from pathlib import Path
  4
  5from boto_session_manager import BotoSesManager
  6
  7import aws_cdk as cdk
  8import aws_cdk.aws_iam as iam
  9import aws_cdk.aws_sqs as sqs
 10import aws_cdk.aws_lambda as lambda_
 11import aws_cdk.aws_lambda_event_sources as event_source
 12from constructs import Construct
 13
 14
 15class Stack(cdk.Stack):
 16    def __init__(
 17        self,
 18        scope: Construct,
 19        id: str,
 20        project_name: str,
 21        **kwargs,
 22    ) -> None:
 23        project_name_slug = project_name.replace("_", "-")
 24        super().__init__(scope, id=id, stack_name=project_name_slug, **kwargs)
 25
 26        self.iam_role_for_lbd = iam.Role(
 27            self,
 28            "IamRoleForLambda",
 29            assumed_by=iam.ServicePrincipal("lambda.amazonaws.com"),
 30            role_name=f"{project_name}-{cdk.Aws.REGION}-lambda-role",
 31            managed_policies=[
 32                iam.ManagedPolicy.from_aws_managed_policy_name("PowerUserAccess")
 33            ],
 34        )
 35
 36        # SQS is declared in the same stack
 37        self.sqs_queue_name = f"{project_name}-queue"
 38        self.sqs_queue = sqs.Queue(
 39            self,
 40            "SQSQueue",
 41            queue_name=self.sqs_queue_name,
 42        )
 43
 44        self.lbd_func_1 = lambda_.Function(
 45            self,
 46            "LambdaFunction1",
 47            function_name=f"{project_name}-1",
 48            code=lambda_.Code.from_asset(f"{dir_lambda_app}"),
 49            handler=f"lambda_function.lambda_handler",
 50            runtime=lambda_.Runtime.PYTHON_3_10,
 51            memory_size=128,
 52            timeout=cdk.Duration.seconds(3),
 53            role=self.iam_role_for_lbd,
 54        )
 55
 56        self.sqs_event_source_1 = event_source.SqsEventSource(
 57            queue=self.sqs_queue,
 58            batch_size=10,
 59            enabled=True,
 60        )
 61        self.lbd_func_1.add_event_source(self.sqs_event_source_1)
 62
 63        # SQS is declared in another stack
 64        self.lbd_func_2 = lambda_.Function(
 65            self,
 66            "LambdaFunction2",
 67            function_name=f"{project_name}-2",
 68            code=lambda_.Code.from_asset(f"{dir_lambda_app}"),
 69            handler=f"lambda_function.lambda_handler",
 70            runtime=lambda_.Runtime.PYTHON_3_10,
 71            memory_size=128,
 72            timeout=cdk.Duration.seconds(3),
 73            role=self.iam_role_for_lbd,
 74        )
 75
 76        sqs_queue = sqs.Queue.from_queue_arn(
 77            self,
 78            "SQSQueueInterface",
 79            queue_arn=f"arn:aws:sqs:{cdk.Aws.REGION}:{cdk.Aws.ACCOUNT_ID}:{self.sqs_queue_name}",
 80        )
 81        self.sqs_event_source_2 = event_source.SqsEventSource(
 82            queue=sqs_queue,
 83            batch_size=10,
 84            enabled=True,
 85        )
 86        self.lbd_func_2.add_event_source(self.sqs_event_source_2)
 87
 88
 89# ------------------------------------------------------------------------------
 90# Config
 91aws_profile = "bmt_app_dev_us_east_1"
 92project_name = "lbd_cdk_event_demo-sqs"
 93# ------------------------------------------------------------------------------
 94
 95dir_workspace = Path(__file__).absolute().parent
 96dir_lambda_app = dir_workspace.joinpath("lambda_app")
 97bsm = BotoSesManager(profile_name=aws_profile)
 98
 99app = cdk.App()
100stack = Stack(app, "MyApp", project_name=project_name)
101
102if __name__ == "__main__":
103    app.synth()

DynamoDB Update#

dynamodb-update.json
 1{
 2    "Records": [
 3        {
 4            "eventID": "c4ca4238a0b923820dcc509a6f75849b",
 5            "eventName": "INSERT",
 6            "eventVersion": "1.1",
 7            "eventSource": "aws:dynamodb",
 8            "awsRegion": "us-east-1",
 9            "dynamodb": {
10                "Keys": {
11                    "Id": {
12                        "N": "101"
13                    }
14                },
15                "NewImage": {
16                    "Message": {
17                        "S": "New item!"
18                    },
19                    "Id": {
20                        "N": "101"
21                    }
22                },
23                "ApproximateCreationDateTime": 1428537600,
24                "SequenceNumber": "4421584500000000017450439091",
25                "SizeBytes": 26,
26                "StreamViewType": "NEW_AND_OLD_IMAGES"
27            },
28            "eventSourceARN": "arn:aws:dynamodb:us-east-1:123456789012:table/ExampleTableWithStream/stream/2015-06-27T00:48:05.899"
29        },
30        {
31            "eventID": "c81e728d9d4c2f636f067f89cc14862c",
32            "eventName": "MODIFY",
33            "eventVersion": "1.1",
34            "eventSource": "aws:dynamodb",
35            "awsRegion": "us-east-1",
36            "dynamodb": {
37                "Keys": {
38                    "Id": {
39                        "N": "101"
40                    }
41                },
42                "NewImage": {
43                    "Message": {
44                        "S": "This item has changed"
45                    },
46                    "Id": {
47                        "N": "101"
48                    }
49                },
50                "OldImage": {
51                    "Message": {
52                        "S": "New item!"
53                    },
54                    "Id": {
55                        "N": "101"
56                    }
57                },
58                "ApproximateCreationDateTime": 1428537600,
59                "SequenceNumber": "4421584500000000017450439092",
60                "SizeBytes": 59,
61                "StreamViewType": "NEW_AND_OLD_IMAGES"
62            },
63            "eventSourceARN": "arn:aws:dynamodb:us-east-1:123456789012:table/ExampleTableWithStream/stream/2015-06-27T00:48:05.899"
64        },
65        {
66            "eventID": "eccbc87e4b5ce2fe28308fd9f2a7baf3",
67            "eventName": "REMOVE",
68            "eventVersion": "1.1",
69            "eventSource": "aws:dynamodb",
70            "awsRegion": "us-east-1",
71            "dynamodb": {
72                "Keys": {
73                    "Id": {
74                        "N": "101"
75                    }
76                },
77                "OldImage": {
78                    "Message": {
79                        "S": "This item has changed"
80                    },
81                    "Id": {
82                        "N": "101"
83                    }
84                },
85                "ApproximateCreationDateTime": 1428537600,
86                "SequenceNumber": "4421584500000000017450439093",
87                "SizeBytes": 38,
88                "StreamViewType": "NEW_AND_OLD_IMAGES"
89            },
90            "eventSourceARN": "arn:aws:dynamodb:us-east-1:123456789012:table/ExampleTableWithStream/stream/2015-06-27T00:48:05.899"
91        }
92    ]
93}

Kinesis Get Records#

kinesis-get-records.json
 1{
 2    "Records": [
 3        {
 4            "kinesis": {
 5                "partitionKey": "partitionKey-03",
 6                "kinesisSchemaVersion": "1.0",
 7                "data": "SGVsbG8sIHRoaXMgaXMgYSB0ZXN0IDEyMy4=",
 8                "sequenceNumber": "49545115243490985018280067714973144582180062593244200961",
 9                "approximateArrivalTimestamp": 1428537600
10            },
11            "eventSource": "aws:kinesis",
12            "eventID": "shardId-000000000000:49545115243490985018280067714973144582180062593244200961",
13            "invokeIdentityArn": "arn:aws:iam::EXAMPLE",
14            "eventVersion": "1.0",
15            "eventName": "aws:kinesis:record",
16            "eventSourceARN": "arn:aws:kinesis:EXAMPLE",
17            "awsRegion": "us-east-1"
18        }
19    ]
20}