발신 계정(B~E) EC2 생성
→ CloudTrail (RunInstances 감지)
→ 발신 계정 EventBridge Rule
→ A 계정 default Event Bus (Cross-account PutEvents)
→ A 계정 EventBridge Rule (이벤트 매칭)
→ SNS Topic
→ SMS 알림
각 발신 계정은 자기 계정 내 모든 리전에 EventBridge Rule을 배포하기 위해 StackSet을 사용합니다.
이 StackSet은 크로스 계정 배포가 아닌, 같은 계정 내 다중 리전 배포(Self-managed) 방식입니다.
발신 계정(B) StackSet
→ us-east-1 : EventBridge Rule + IAM Role 배포
→ ap-northeast-2 : EventBridge Rule + IAM Role 배포
→ eu-west-1 : EventBridge Rule + IAM Role 배포
→ (모든 대상 리전...)
발신 계정(C) StackSet → (동일 구조)
발신 계정(D) StackSet → (동일 구조)
...
| 역할 | 계정 ID | 설명 |
|---|---|---|
| A (중앙/수신) | <A_ACCOUNT_ID> | 모든 이벤트를 수신하는 계정 |
| B (발신) | <B_ACCOUNT_ID> | EC2 생성을 감지하는 하위 계정 |
| C (발신) | <C_ACCOUNT_ID> | 하위 계정 |
| D (발신) | <D_ACCOUNT_ID> | 하위 계정 |
| E (발신) | <E_ACCOUNT_ID> | 하위 계정 |
| 구성 요소 | A 계정 (수신) | B~E 계정 (발신) |
|---|---|---|
| Event Bus 리소스 정책 | ✅ | — |
| EventBridge Rule (수신) | ✅ | — |
| SNS Topic + 구독 | ✅ | — |
| 입력 변환기 | ✅ | — |
| StackSet용 IAM Role 2개 | — | ✅ (각 계정마다) |
| StackSet 배포 | — | ✅ (각 계정마다) |
| CloudTrail Trail | — | ✅ (각 계정마다) |
경로: A 계정 → Amazon EventBridge → 이벤트 버스 → default → 편집 → 리소스 기반 정책
발신 계정들이 A 계정의 Event Bus에 이벤트를 보낼 수 있도록 허용합니다.
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "AllowCrossAccountEvents",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::<B_ACCOUNT_ID>:root",
"arn:aws:iam::<C_ACCOUNT_ID>:root",
"arn:aws:iam::<D_ACCOUNT_ID>:root",
"arn:aws:iam::<E_ACCOUNT_ID>:root"
]
},
"Action": "events:PutEvents",
"Resource": "arn:aws:events:us-east-1:<A_ACCOUNT_ID>:event-bus/default"
}]
}
새 발신 계정을 추가할 때는
Principal.AWS배열에 해당 계정의 ARN을 추가합니다.
이 단계는 모든 발신 계정(B, C, D, E)에서 각각 수행해야 합니다.
각 발신 계정이 자기 계정 내 모든 리전에 EventBridge Rule을 StackSet으로 배포하기 위한 IAM 구성입니다.
| Role 이름 | 신뢰 엔터티 | 연결 정책 | 용도 | 설명 |
|---|---|---|---|---|
AWSCloudFormationStackSetAdministrationRole | AWS 서비스 (cloudformation.amazonaws.com) | StackSetAdminPolicy | StackSet 관리용 | CloudFormation 서비스가 Assume하여 StackSet 작업을 시작 |
AWSCloudFormationStackSetExecutionRole | AWS 계정 (자기 자신의 계정 ID) | StackSetExecutionPolicy | StackSet 실행용 | AdministrationRole이 Assume하여 각 리전에 스택을 배포 |
CloudFormation 서비스
→ AdministrationRole Assume (신뢰: cloudformation.amazonaws.com)
→ ExecutionRole Assume (신뢰: 자기 계정 ID)
→ 각 리전에 EventBridge Rule + IAM Role 생성
경로: IAM 콘솔 → 역할 → 역할 생성 → AWS 서비스 선택 → CloudFormation
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"Service": "cloudformation.amazonaws.com"
},
"Action": "sts:AssumeRole"
}]
}
StackSetAdminPolicy경로: IAM 콘솔 → 정책 → 정책 생성 → JSON 탭
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AssumeExecutionRole",
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::*:role/AWSCloudFormationStackSetExecutionRole"
}
]
}
이 정책은 동일 계정 내 ExecutionRole을 Assume하기 위한 것입니다.
Resource의*는 계정 ID 부분이며, 같은 계정 내에서 동작합니다.
경로: IAM 콘솔 → 역할 → 역할 생성 → AWS 계정 선택 → 이 계정 (자기 자신의 계정 ID)
⚠️ 아래의
<자기_계정_ID>를 현재 작업 중인 발신 계정의 실제 계정 ID로 교체하세요.
예: B 계정에서 작업 중이라면<B_ACCOUNT_ID>, C 계정이라면<C_ACCOUNT_ID>
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::<자기_계정_ID>:root"
},
"Action": "sts:AssumeRole"
}]
}
StackSetExecutionPolicy⚠️ 아래 정책의 모든
<자기_계정_ID>를 현재 작업 중인 발신 계정의 실제 계정 ID로 교체하세요.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "CloudFormationManagement",
"Effect": "Allow",
"Action": [
"cloudformation:CreateStack",
"cloudformation:UpdateStack",
"cloudformation:DeleteStack",
"cloudformation:DescribeStacks",
"cloudformation:DescribeStackEvents",
"cloudformation:GetTemplate",
"cloudformation:ListStackResources"
],
"Resource": "arn:aws:cloudformation:*:<자기_계정_ID>:stack/StackSet-*"
},
{
"Sid": "EventBridgeRuleManagement",
"Effect": "Allow",
"Action": [
"events:PutRule",
"events:DeleteRule",
"events:DescribeRule",
"events:PutTargets",
"events:RemoveTargets",
"events:EnableRule",
"events:DisableRule",
"events:ListTargetsByRule"
],
"Resource": "arn:aws:events:*:<자기_계정_ID>:rule/ec2-creation-alert-rule"
},
{
"Sid": "IAMRoleManagement",
"Effect": "Allow",
"Action": [
"iam:CreateRole",
"iam:DeleteRole",
"iam:GetRole",
"iam:PutRolePolicy",
"iam:DeleteRolePolicy",
"iam:GetRolePolicy",
"iam:PassRole",
"iam:TagRole",
"iam:UntagRole"
],
"Resource": "arn:aws:iam::<자기_계정_ID>:role/EventBridge-CrossAccount-*"
},
{
"Sid": "SNSNotification",
"Effect": "Allow",
"Action": [
"sns:Publish"
],
"Resource": "arn:aws:sns:*:<자기_계정_ID>:StackSet-*"
}
]
}
| Sid | 용도 |
|---|---|
CloudFormationManagement | StackSet이 배포하는 개별 스택의 생성/수정/삭제/조회 |
EventBridgeRuleManagement | EC2 생성 알림용 EventBridge 규칙 관리 |
IAMRoleManagement | EventBridge 크로스 계정 역할 생성/삭제 및 PassRole |
SNSNotification | StackSet 관련 SNS 토픽에 알림 발행 |
이 단계는 모든 발신 계정(B, C, D, E)에서 각각 수행해야 합니다.
StackSet은 같은 계정 내 여러 리전에 동일한 리소스를 한 번에 배포하기 위해 사용합니다.
StackSet 이름 추천 : ec2-creation-alert-stackset
아래 CloudFormation 템플릿을 StackSet으로 배포합니다.
파일명: ec2-alert-rule.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: >-
EC2 instance creation alert - forward to central account
Resources:
EC2CreationAlertRule:
Type: AWS::Events::Rule
Properties:
Name: ec2-creation-alert-rule
Description: >-
Detect EC2 RunInstances and forward to central account
State: ENABLED
EventPattern:
source:
- aws.ec2
detail-type:
- AWS API Call via CloudTrail
detail:
eventSource:
- ec2.amazonaws.com
eventName:
- RunInstances
Targets:
- Id: CentralAccountEventBus
Arn: arn:aws:events:us-east-1:<A_ACCOUNT_ID>:event-bus/default
RoleArn: !GetAtt EventBridgeRole.Arn
EventBridgeRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub 'EventBridge-CrossAccount-${AWS::Region}'
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: events.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: PutEventsPolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action: events:PutEvents
Resource: arn:aws:events:us-east-1:<A_ACCOUNT_ID>:event-bus/default
이 템플릿은 두 가지 리소스를 생성합니다:
1. EventBridge Rule — EC2 RunInstances API 호출을 감지하여 A 계정으로 전달
2. IAM Role — EventBridge가 A 계정의 Event Bus에 PutEvents를 실행할 수 있는 권한
이 단계를 빠뜨리면 EventBridge Rule이 트리거되지 않습니다.
이 단계는 모든 발신 계정(B, C, D, E)에서 각각 수행해야 합니다. (이미 Trail이 있는 계정은 생략)
AWS API Call via CloudTrail 이벤트가 EventBridge로 전달되려면 활성화된 CloudTrail Trail이 반드시 필요합니다.
경로: 각 발신 계정 → CloudTrail → 추적 → 추적 생성
| 항목 | 설정 값 |
|---|---|
| 추적 이름 | management-events-trail |
| 다중 리전 | 예 (콘솔 생성 시 자동) |
| S3 버킷 | 새 버킷 생성 (기본값) |
| SSE-KMS 암호화 | 비활성화 (비용 절감, S3 기본 SSE-S3 암호화 적용됨) |
| 로그 파일 검증 | 활성화 |
| CloudWatch Logs | 비활성화 (불필요) |
| 이벤트 유형 | 관리 이벤트 |
| API 활동 | 읽기 + 쓰기 |
경로: A 계정 → Amazon EventBridge → 규칙 → 규칙 생성
| 항목 | 값 |
|---|---|
| 규칙 이름 | ec2-creation-alert-rule |
| 이벤트 버스 | default |
| 상태 | 활성화 |
{
"source": ["aws.ec2"],
"detail-type": ["AWS API Call via CloudTrail"],
"detail": {
"eventSource": ["ec2.amazonaws.com"],
"eventName": ["RunInstances"]
}
}
| 항목 | 값 |
|---|---|
| 대상 유형 | SNS 주제 |
| 대상 | ec2-instance-creation-alert |
이 설정이 없으면 CloudTrail 원본 JSON(수천 자)이 그대로 SMS로 전송되어 10건 이상 분할됩니다.
경로: A 계정 → EventBridge → ec2-creation-alert-rule → 대상 편집 → 입력 변환 → 입력 변환기
{"account":"$.account","region":"$.region","instanceId":"$.detail.responseElements.instancesSet.items[0].instanceId","time":"$.time"}
"EC2 Created: account=<account>, region=<region>, instance=<instanceId>, time=<time>"
SMS는 영문 160자 / 한글 70자 제한이 있으므로, 메시지를 짧게 유지해야 1건으로 수신됩니다. 영문 템플릿을 권장합니다.
경로: A 계정 → SNS → 주제 → ec2-instance-creation-alert
| 프로토콜 | 엔드포인트 | 비고 |
|---|---|---|
| SMS | 전화번호 (예: +8201012345678) | 확인 불필요 |
| 이메일 주소 | 확인 메일 클릭 필요 |