정책 리스크를 파악하십시오. 정책에 대한 질문을 일상 언어로 하십시오. 데모 신청하기 →
Published:
CloudTrail과 CloudWatch Events가 함께 동작하는 지나치게 복잡한 방식
by FireMon
제 클라우드 여정에서 가장 골치 아팠던 문제 중 하나는 CloudTrail과 CloudWatch Events가 어떻게 함께 동작하는지 이해하는 것이었습니다. 어떤 이유에서인지 이 연동이 실제로 어떻게 이루어지는지, 특히 멀티 리전 및 AWS Organization 추적(trail) 개념과 어떻게 맞물리는지 이해하는 데 수년이 걸렸고 수많은 테스트가 필요했습니다. 그리고 모든 것을 파악하고 나서는 다들 이미 알고 있으리라 생각했지만, 최근의 대화들을 통해 이러한 혼란이 꽤 흔하다는 점이 분명해졌습니다. 그래서 이를 최대한 단순하게 정리해 보고자 합니다.
먼저, 우리가 해결하려는 문제는 다음과 같습니다. CloudTrail 이벤트를 기반으로 CloudWatch 규칙을 만들고, 이를 사용해 알림을 보내거나 Lambda 함수를 트리거하는 것입니다.
그게 전부입니다. 저는 새 보안 그룹 규칙을 여는 API 호출(궁금하실까 봐 말씀드리면 AuthorizeSecurityGroupIngress입니다)처럼 단순한 작업에 대해 알림을 보내고 싶을 뿐입니다.
이를 구현하려면 다음이 갖추어져 있어야 합니다.
- API 호출이 이루어지는 리전에서 CloudTrail이 활성화되어 있어야 합니다.
- CloudTrail이 CloudWatch로 스트리밍되어야 합니다.
- 해당 API 호출 또는 모든 CloudTrail API 호출을 탐지하는 CloudWatch 규칙이 API 호출이 이루어지는 리전에 있어야 합니다.
이제 혼란스러운 부분입니다.
- 멀티 리전 CloudTrail이나 Organization 추적을 생성하면, 이면에서 AWS는 실제로 모든 개별 리전(Organization 추적의 경우 모든 계정)에 추적을 설정합니다. 이들은 모두 별개의 추적이며, 각각이 결과를 공유 S3 버킷으로 전송하도록 구성되어 있고, 각 추적은 해당 홈 계정과 리전에서만 관리할 수 있습니다.
- 그러나 API 호출에 대한 CloudWatch 이벤트는 해당 API 호출이 이루어진 리전에서만 생성됩니다입니다.
- 따라서 멀티 리전 추적을 생성하면 데이터는 모두 중앙에서 수집되지만, 이벤트는 로컬에서만 나타납니다. 홈 추적이 있는 리전의 CloudWatch 규칙은 해당(홈) 리전에서 이루어진 API 호출에 대해서만 트리거됩니다. 그러므로 보안 그룹 변경에 대한 경보를 구성하더라도, CloudTrail이 켜져 있음에도 다른 리전이 아닌 홈 리전에서만 작동합니다.
- CloudWatch 로그 그룹/스트림은 다른 리전이 아닌 기본 리전에 나타나지만, 각 이벤트는 해당 이벤트를 발생시킨 리전에서 생성됩니다.
- API 호출에 대한 모든 이벤트를 수집하려면 문서화되지 않은 이벤트 정의(아래에 붙여 두었습니다)를 사용해야 합니다.
- Amazon의 문서를 읽어 보아도… 이런 내용을 명확하게 설명한 곳은 없습니다. 적어도 제가 찾을 수 있었던 범위에서는 그렇습니다. 실제로 언젠가 지원 통화 중에 제가 이를 알아냈는데, 제 이벤트가 들어오기 시작하는 동안 AWS 담당자는 계속 “그렇게 동작하지 않을 텐데요”라고 중얼거렸습니다. 그분에게는 힘든 밤이었을 것입니다.
어떤 이유에서인지 이 부분은 저에게 전혀 직관적이지 않았습니다. 추적을 중앙화하면 CloudWatch 규칙도 중앙화하여 API 호출 이벤트로 트리거할 수 있으리라 생각했습니다. 안타깝게도 이는 완전히 잘못된 생각이었고, 추적을 중앙화하더라도 관심 있는 모든 리전에 규칙을 생성해야 합니다. 여러 계정의 이벤트를 수집하기 위해 Event Bus를 사용하더라도, 여전히 모든 계정의 모든 리전에 CloudWatch 규칙을 생성해 이벤트를 Bus로 전송해야 하며, 그런 다음 원하는 알림/작업을 트리거하려면 Event Bus의 모든 리전에 규칙을 구성해야 합니다.
CloudWatch 규칙이 지원하는 준실시간 경보 기능이나 자동 교정/작업을 원하신다면, 다음과 같이 접근하시기를 권장합니다.
- 멀티 리전 추적을 켭니다. 이 작업은 한 번만 하면 되며, Organization 추적으로 충분합니다.
- 이렇게 하면 필요한 모든 리전별 추적이 생성됩니다. 하나의 중앙 추적처럼 보이지만, 실제로는 데이터를 중앙 수신처로 보내는 리전별 추적의 모음입니다.
- 옵션 1: 준실시간 경보가 필요한 모든 리전에 CloudWatch 규칙을 생성합니다. 이때 CloudFormation과 Terraform이 도움이 됩니다.
- 옵션 2: 모든 이벤트를 중앙화합니다. 각 리전에서 모든 CloudTrail 이벤트를 Lambda 함수 또는 SNS 주제로 전송하는 규칙을 생성하고, 이를 통해 원하는 대상으로 전달합니다. 저희도 이 기법을 사용하고 있습니다. 저희는 사용자 지정 API 엔드포인트를 통해 전송하지만, Kinesis를 비롯해 거의 무엇으로든 스트리밍할 수 있습니다.
시작에 도움이 되도록 두 가지 코드 샘플을 제공합니다.
CloudTrail의 모든 이벤트를 수집하기 위한 CloudWatch 규칙의 비공개 필터 패턴:
{
"detail-type": [
"AWS API Call via CloudTrail"
] }
그리고 다음은 이벤트를 전달하는 Lambda 코드 샘플로, 여기서는 Kinesis로 전달하는 예입니다.
import json
import boto3
def lambda_handler(event, context):
kinesis = boto3.client('kinesis', region_name='us-west-2')
data = json.dumps(event)
print(data)
response = kinesis.put_record(
StreamName='cloudsec_prod_stream_alert_kinesis',
Data=data,
PartitionKey='test-client-id'
)
print(response)
return {
'statusCode': 200,
'body': json.dumps('Record added')
}