AWS SAM CLI를 통한 EventBridge-Lambda 결합과 배포
RECOMMEND POSTS BEFORE THIS
1. Context
최근 서포트 했던 팀은 PDF를 이미지로 만드는 작업이 필요했다. PDF 파일 용량이 20MB~30MB 정도로 컸기 때문에 S3에 업로드하면 오브젝트 생성 이벤트를 AWS 람다(lambda)에서 수신해서 처리하기러 했다. S3에 파일을 업로드 했을 때 람다에서 이벤트를 수신 받을 수 있는 방법은 두 가지 있다.
- S3 이벤트 알림(event notification)
- S3 버킷에서 직접 람다 함수를 이벤트 수신 대상으로 지정한다.
- 이벤트 브릿지(AWS EventBridge)
- S3 이벤트를 이벤트 브릿지에 전달한다.
- 이벤트 브릿지는 지정된 규칙에 따라 람다로 이벤트를 전달한다.
파일 업로드 이벤트가 하나의 람다가 아닌 다른 람다에서도 필요했다. 아쉽게도 S3 이벤트 알림은 하나의 이벤트를 동시에 여러 대상에 전송할 수 없기 때문에 이벤트 브릿지를 사용했다. AWS EventBridge는 서버리스 이벤트 버스 서비스로 애플리케이션 간이 이벤트 기반 통합(evnet driven integration)을 코드 없이 쉽게 구현할 수 있도록 돕는 컴포넌트다. 작성한 규칙에 따라 지정된 타겟으로 이벤트를 전달한다.
최종적으로 필요한 구조는 다음과 같다.
- S3 스토리지에 PDF 파일을 업로드한다.
- PDF 파일 업로드 되면 경우 지정된 타겟 람다 애플리케이션으로 이벤트를 전달한다.

2. Template for AWS SAM CLI
IaC(infrastructure as code)로 AWS SAM(Serverless Application Model)를 사용했다. 위에서 언급한 구조를 만들기 위한 예제 코드를 살펴보자. 간소화 된 프로젝트를 구조는 다음과 같다.
- target-1, target-2 디렉토리에는 람다 핸들러가 포함된다.
$ tree -I ".aws-sam|.idea|.venv|venv" .
.
├── __init__.py
├── samconfig.toml
├── target-1
│ ├── __init__.py
│ └── handler.py
├── target-2
│ ├── __init__.py
│ └── handler.py
└── template.yaml
파이썬 코드에선 간단한 로그를 출력하고, 어떤 핸들러에서 어떤 요청을 처리했는지에 대한 내용이 담긴 메시지를 반환한다.
import json
def lambda_handler(event, context):
print(f"Hello, I am a first target. - {json.dumps(event)}")
return {
"statusCode": 200,
"body" : f"Hello, I am a first target. - {json.dumps(event)}"
}
처음 구성한 템플릿은 다음과 같다. 설명은 주석에 포함한다.
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: A simple SAM app with Lambda
Globals:
# 람다 함수 리소스 스펙
Function:
Timeout: 5
MemorySize: 128
Runtime: python3.13
Resources:
# AWS S3 버킷
S3Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: event-bridge-bucket-name
# 이벤트 브릿지로 이벤트를 보내기 위한 설정
NotificationConfiguration:
EventBridgeConfiguration:
EventBridgeEnabled: true
# 첫번째 타겟 람다
FirstTargetLambda:
Type: AWS::Serverless::Function
Properties:
CodeUri: target-1/
Handler: handler.lambda_handler
Events:
# 이벤트 브릿지 규칙
UploadEvent:
Type: EventBridgeRule
Properties:
Pattern:
# 소스 S3
source:
- aws.s3
# 오브젝트 생성 이벤트
detail-type:
- "Object Created"
detail:
# S3 버킷 레퍼런스
bucket:
name:
- !Ref S3Bucket
# 접미사가 .pdf 파일만 대상으로 필터링
object:
key:
- suffix: ".pdf"
EventBusName: default
# 두번째 타겟 람다
SecondTargetLambda:
Type: AWS::Serverless::Function
Properties:
CodeUri: target-2/
Handler: handler.lambda_handler
Events:
UploadEvent:
Type: EventBridgeRule
Properties:
Pattern:
source:
- aws.s3
detail-type:
- "Object Created"
detail:
bucket:
name:
- !Ref S3Bucket
object:
key:
- suffix: ".pdf"
EventBusName: default
위 템플릿을 빌드한다.
$ sam build
Starting Build use cache
Building codeuri: /Users/junhyunny/Desktop/action-in-blog/target-1 runtime: python3.13 architecture: x86_64 functions: FirstTargetLambda
Building codeuri: /Users/junhyunny/Desktop/action-in-blog/target-2 runtime: python3.13 architecture: x86_64 functions: SecondTargetLambda
requirements.txt file not found. Continuing the build without dependencies.
requirements.txt file not found. Continuing the build without dependencies.
Running PythonPipBuilder:CopySource
Running PythonPipBuilder:CopySource
Build Succeeded
Built Artifacts : .aws-sam/build
Built Template : .aws-sam/build/template.yaml
Commands you can use next
=========================
[*] Validate SAM template: sam validate
[*] Invoke Function: sam local invoke
[*] Test Function in the Cloud: sam sync --stack-name --watch
[*] Deploy: sam deploy --guided
빌드가 완료되면 이를 배포한다.
- 각 타겟 람다에 대한 Permission, Rule 리소스가 생성된다.
$ sam deploy
...
CloudFormation stack changeset
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Operation LogicalResourceId ResourceType Replacement
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ Add FirstTargetLambdaRole AWS::IAM::Role N/A
+ Add FirstTargetLambdaUploadEventPermission AWS::Lambda::Permission N/A
+ Add FirstTargetLambdaUploadEvent AWS::Events::Rule N/A
+ Add FirstTargetLambda AWS::Lambda::Function N/A
+ Add S3Bucket AWS::S3::Bucket N/A
+ Add SecondTargetLambdaRole AWS::IAM::Role N/A
+ Add SecondTargetLambdaUploadEventPermission AWS::Lambda::Permission N/A
+ Add SecondTargetLambdaUploadEvent AWS::Events::Rule N/A
+ Add SecondTargetLambda AWS::Lambda::Function N/A
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
...
Previewing CloudFormation changeset before deployment
======================================================
Deploy this changeset? [y/N]: y
2025-05-25 00:56:23 - Waiting for stack create/update to complete
CloudFormation events from stack operations (refresh every 5.0 seconds)
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ResourceStatus ResourceType LogicalResourceId ResourceStatusReason
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
CREATE_IN_PROGRESS AWS::CloudFormation::Stack sam-app User Initiated
...
CREATE_COMPLETE AWS::CloudFormation::Stack sam-app -
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Successfully created/updated stack - sam-app in ap-northeast-1
배포가 완료된 후 이벤트 브릿지를 보면 두 개의 규칙이 생성된 것을 확인할 수 있다.

람다 리소스 하위 이벤트에 직접 규칙을 설정하면 각 람다에 대한 허가(permission)과 규칙(rule)이 별도로 생성된다.

두 람다에 대해 동일한 규칙을 지정하려면 다음과 같이 템플릿을 변경한다.
- 아래 템플릿을 배포하면 하나의 이벤트 브릿지 규칙과 각 람다를 수행하기 위한 두 개의 권한이 생성된다.
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: A simple SAM app with Lambda
Globals:
# 람다 함수 리소스 스펙
Function:
Timeout: 5
MemorySize: 128
Runtime: python3.13
Resources:
# AWS S3 버킷
S3Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: event-bridge-bucket-name
# 이벤트 브릿지로 이벤트를 보내기 위한 설정
NotificationConfiguration:
EventBridgeConfiguration:
EventBridgeEnabled: true
# EventBridge 규칙
UnifiedS3EventRule:
Type: AWS::Events::Rule
Properties:
Name: "lambda-file-upload-event"
# 이벤트 패턴
EventPattern:
source:
- aws.s3
detail-type:
- "Object Created"
detail:
bucket:
name:
- !Ref S3Bucket
object:
key:
- suffix: ".pdf"
# 이벤트 규칙 타겟 지정
Targets:
- Id: !Ref FirstTargetLambda
Arn: !GetAtt FirstTargetLambda.Arn
- Id: !Ref SecondTargetLambda
Arn: !GetAtt SecondTargetLambda.Arn
# 첫번째 타겟 람다 실행을 위한 permission
PermissionForEventsToInvokeLambda:
Type: AWS::Lambda::Permission
Properties:
FunctionName: !Ref FirstTargetLambda
Action: lambda:InvokeFunction
Principal: events.amazonaws.com
SourceArn: !GetAtt UnifiedS3EventRule.Arn
# 두번째 타겟 람다 실행을 위한 permission
PermissionForSeccondEventsToInvokeLambda:
Type: AWS::Lambda::Permission
Properties:
FunctionName: !Ref SecondTargetLambda
Action: lambda:InvokeFunction
Principal: events.amazonaws.com
SourceArn: !GetAtt UnifiedS3EventRule.Arn
# 첫번째 타겟 람다
FirstTargetLambda:
Type: AWS::Serverless::Function
Properties:
CodeUri: target-1/
Handler: handler.lambda_handler
# 두번째 타겟 람다
SecondTargetLambda:
Type: AWS::Serverless::Function
Properties:
CodeUri: target-2/
Handler: handler.lambda_handler
위 템플릿을 배포하면 다음과 같은 규칙 정보를 확인할 수 있다.

해당 규칙의 대상(target)을 보면 두 개의 람다가 연결된 것을 볼 수 있다.

최종적으로 시스템은 다음과 같이 결합된다.

CLOSING
S3에 확장자가 .pdf
인 파일을 업로드하면 각 람다 함수가 트리거(trigger)되지만, 이 외에 파일 업로드에는 반응하지 않는다. AWS 클라우드워치(CloudWatch)에서 로그를 확인하면 두 타겟 람다에 이벤트가 모두 전달된 것을 확인할 수 있다.
댓글남기기