today's helen

seize!

aws

[AWS] CloudTrail을 이용한 AWS 사용자 활동 추적과 로그 분석

yooncandooit 2026. 7. 10. 13:15
반응형

요약: aws에서 누가, 언제, 무엇을 했는지 알고 싶다면 CloudTrail 로그를 보기


지난 글에서는 누구에게 무엇을 허용할 것인지를 다뤘는데, 이번 글은

"실제로 누가 무엇을 했는가"

에 대한 내용이다

  Presigned URL CloudTrail
질문 누구에게 무엇을 허용할까 누가 실제로 무엇을 했을까
성격 사전 통제 사후 탐지
시점 사건 전 사건 후

권한을 아무리 잘 설계해도 누가 언제 그걸 바꿔버렸는지 추적할 수 없으면 의미가 없고,

반대로 로그만 잔뜩 쌓아둬도 의미가 없으니 막을 수단이 있어야한다


CloudTrail이란

aws 작업을 감사하는 서비스로, api 호출과 사용자 활동을 자동으로 기록해준다

기록되는 주요 사건의 마지막 두 개를 눈여겨봐야하는데

IAM 권한, 버킷 정책 등 설계한 통제 장치들이 누군가에 의해 바뀌었는지를 감시하는 게 CloudTrail이다

모든 AWS 작업은 API 호출이다

이게 CloudTrail을 이해하는 핵심인 것 같다

콘솔에서 버튼 클릭
cli 명령어 입력      ──▶  StopInstances api 호출  ──▶  CloudTrail json 기록
terraform apply

콘솔의 예쁜 버튼 아래엔 결국 api가 있을 뿐이니, 어떤 도구를 쓰든 eventName은 똑같이 기록된다

CloudTrail 하나로 도구와 무관하게 모든 활동을 잡아낼 수 있는 이유!


실습

이번 실습은 직접 사건을 만들고, 그 흔적을 읽는 순서로 진행했다

1. IAM 계정 확인

루트 계정으로 실습해도 되긴 하지만, 감사 로그를 다루는 실습에서 루트를 쓰는 건 좀 아이러니하니까 lab-user를 따로 만들자

AdministratorAccess가 붙어 있는지 확인하고, 없다면 직접 정책 연결로 붙여주면 된다

cf. 실무에서는 AdministratorAccess를 이렇게 막 주면 안 된다

로그를 볼 사람과 로그를 끌 수 있는 사람은 반드시 분리되어야 하기 때문

2. EC2 인스턴스 생성

CloudTrail-Lab이라는 이름으로 t3.micro (혹은 t2.micro) 하나만 띄운다. Amazon Linux 2023에 키 페어 없음, 스토리지는 기본 8GiB로 두면 됨

3. CloudTrail 추적 생성

Security-Lab이라는 이름으로 빠른 추적 생성을 누르면 끝난다

로그가 저장될 s3 버킷은 자동으로 만들어지고, 이벤트를 로깅하는 것 자체에는 비용이 들지 않지만 로그를 저장하는 s3 버킷에는 요금이 발생한다는 안내가 뜬다

4. 인스턴스 중지

ec2로 돌아가서 방금 만든 인스턴스를 중지시키고,

다시 CloudTrail의 이벤트 기록으로 이동해 StopInstances를 검색해보자

방금 내가 한 행동(StopInstances)이 로그로 남아 있다!


json 코드 분석하기

이벤트를 클릭하면 아래 같은 json이 나온다

해당 이벤트 하나에 육하원칙이 거의 다 들어 있었다

질문 필드
누가 userIdentity.type / arn / userName
언제 eventTime
어디서 sourceIPAddress / awsRegion
무엇을 eventName / eventSource
무엇에 대해 resources[].ARN
어떻게 userAgent / sessionCredentialFromConsole
결과는 responseElements.currentState
위험한가 readOnly

readOnly를 보자!

"readOnly": false

읽기 전용 작업인지 알려주는 필드로,

api readOnly 의미
DescribeInstances true 조회만
GetBucketPolicy true 조회만
StopInstances false 상태 변경
DeleteBucket false 리소스 변경

수만 건의 로그에서 "진짜 문제가 될 만한 것"만 걸러내는 첫 번째 필터라서, 보안 관제에서 제일 먼저 거는 조건이라고 한다

다만 readOnly: true인 이벤트를 아예 안 봐도 되는 건 아니다. DescribeInstancesListBuckets 같은 조회 api가 비정상적으로 폭주하는 건 정찰의 전형적인 신호이기도 하다

requestID와 eventID의 차이

비슷해 보이는데 역할이 다르다

  • requestID : aws가 해당 api 요청에 부여한 id로, aws에 문의할 때 쓴다
  • eventID : CloudTrail 이벤트 자체의 고유 id로, 로그 추적하고 분석할 때 쓴다

previousState → currentState

"currentState":  { "code": 64, "name": "stopping" },
"previousState": { "code": 16, "name": "running" }

상태 변화의 전후를 통째로 담고 있어서, 로그만 보고도 "실행 중이던 인스턴스가 중지되었다"는 걸 알 수 있다

mfaAuthenticated

"mfaAuthenticated": "false"

실제 운영 계정이었다면 이 false가 경보 대상이다

많은 조직이 CloudTrail 로그에서 mfaAuthenticated: false인 콘솔 로그인을 알람 조건으로 걸어둔다고 한다


실패한 API 호출이 더 많은 걸 말해준다

CloudTrail은 성공한 호출만 기록하는 게 아니라 실패한 api 호출도 기록한다

권한 없이 s3 버킷을 삭제하려고 시도하면 AccessDenied와 함께 이벤트가 남는데, 사실 이게 CloudTrail의 진짜 가치인 것 같다

탈취한 키로 접속
  → GetCallerIdentity   (성공)      "나는 누구지?"
  → ListUsers           (AccessDenied)
  → ListRoles           (AccessDenied)
  → ListBuckets         (성공)      ← 여기서 뚫림
  → GetObject × 수백 건  (성공)      ← 데이터 유출

성공 직전의 실패 더미가 침해의 가장 선명한 지문이 되는 셈이다!

반대로 실패가 없어서 위험한 경우도 있다

AdministratorAccess를 가진 계정이 탈취되면 아무것도 실패하지 않아서 로그만으론 정상 관리자와 구분이 안 된다

최소 권한 원칙이 곧 탐지 가능성이기도 한 것

GuardDuty가 하는 일이 정확히 이건데, Recon:IAMUser/MaliciousIPCaller 같은 탐지 항목이 전부 CloudTrail의 실패 이벤트를 먹고 동작한다


로그를 실제로 쓰는 방법

실습에서는 콘솔의 이벤트 기록까지만 봤지만, 콘솔은 90일치 관리 이벤트만 보여주기 때문에 실무에서는 단계가 올라간다

단계 도구 용도
1 CloudTrail 콘솔 이벤트 기록 최근 90일, 단건 조회
2 s3 + Athena 장기 로그를 sql로 검색
3 CloudWatch Logs + Metric Filter + Alarm 특정 이벤트 발생 시 즉시 알림
4 EventBridge + Lambda 위험 이벤트 자동 차단·롤백
5 GuardDuty / Security Hub ml 기반 이상 탐지

특히 3번이 가성비가 좋다고 한다. DeleteTrail, StopLogging, DeleteBucket, Root 계정 로그인 같은 이벤트가 발생하면 sns로 즉시 알림을 받는 것인데, 이 몇 줄짜리 설정이 실무 보안의 기본이라고 한다

-- Athena로 Root 계정의 위험 작업만 뽑아보기
SELECT eventtime, useridentity.arn, eventname, errorcode
FROM cloudtrail_logs
WHERE useridentity.type = 'Root'
  AND readonly = false

실습 화면 상단에 "CloudTrail Lake가 2026년 5월 31일부터 신규 고객에게 제공되지 않는다"는 배너가 떠 있었는데,

유사 기능은 CloudWatch를 참고하라고 하니, 앞으로는 CloudWatch Logs 쪽 파이프라인에 익숙해지는 게 유리해 보인다

관리 이벤트 vs 데이터 이벤트

CloudTrail 기본 설정으로는 s3 파일을 누가 다운로드했는지가 기록되지 않는다

  • 관리 이벤트 : PutBucketPolicy, CreateBucket 처럼 리소스를 관리하는 작업으로 기본 활성화되어 있다
  • 데이터 이벤트 : GetObject, PutObject 처럼 데이터를 다루는 작업인데 별도로 켜야 하고 유료

(지난 글의 presigned url과 연결하면, 데이터 이벤트를 켜야 발급된 url로 누가 언제 파일을 받아갔는지 추적할 수 있다)


로그 버킷이 공격당하면 어떡할까

로그를 지울 수 있는 사람은 흔적도 지울 수 있다는 게 감사 시스템의 근본 딜레마다

실습에서도 마지막에 추적을 삭제하고 s3 버킷을 비우고 지웠는데, 공격자가 계정 권한을 얻으면 똑같이 할 수 있는 것 아닌가?

실무에서는 여러 레이어로 막는다

1. 계정 분리 (제일 중요)

[운영 계정 A] ─┐
[운영 계정 B] ─┼──▶ [로그 아카이브 전용 계정]  ← 로그 버킷은 여기에만
[운영 계정 C] ─┘        (운영팀은 접근 권한 없음)

운영 계정이 통째로 털려도 로그는 다른 계정에 있어서 손댈 수 없다

2. s3 Object Lock

지정 기간 동안 Root 계정조차 삭제/수정 불가하도록 만든다. worm(Write Once Read Many) 스토리지가 되는 것

3. Log File Validation

CloudTrail이 1시간마다 로그 파일의 sha-256 해시를 모아 다이제스트 파일을 만들고 aws 비공개 키로 서명한다

로그가 조작되면 해시가 안 맞고 파일이 사라지면 다이제스트에 구멍이 나기 때문에, 삭제를 막진 못해도 삭제된 사실은 증명된다

4. scp로 봉쇄

Organizations 서비스 제어 정책으로 cloudtrail:StopLogging, cloudtrail:DeleteTrail을 조직 전체에서 deny

5. 데드맨 스위치

CloudWatch Alarm
  Metric: CloudTrail 이벤트 수
  조건: 15분간 이벤트 0건
  TreatMissingData: breaching ← 데이터가 없으면 경보

정상이라면 최소한 몇 건은 흐르기 때문에, 침묵 자체가 신호가 된다

그리고 애초에 CloudTrail을 끄는 행위인 StopLogging, DeleteTrail도 CloudTrail에 기록되기 때문에 완벽한 은폐는 어려운 구조다


왜 RDS가 아니라 S3일까?

CloudTrail 추적을 만들면 s3 버킷이 자동으로 생기는데, 왜 하필 s3일까?

로그의 성격이 관계형 데이터베이스와 안 맞기 때문이다

특성 CloudTrail 로그 rds가 잘하는 일
쓰기 한 번 쓰고 안 고침 잦은 update/delete
읽기 사고 났을 때 가끔, 대량 스캔 수시로, 소량 정밀 조회
스키마 서비스마다 구조가 다름 고정 스키마
볼륨 큰 조직은 하루 수억 건 gb~tb
보관 규정상 수년 보통 짧음
- 비용 : s3 Standard는 gb당 월 $0.023인데 rds 스토리지는 그 5~10배에 인스턴스 시간당 요금이 상시 발생해서, 1년에 몇 번 볼 로그를 위해 db를 24시간 켜둘 이유가 없음    
- 스키마 부재 : ec2는 instancesSet, s3는 bucketName, iam은 또 다른 구조라서 수백 개 서비스의 파라미터를 하나의 테이블로 정규화하는 건 불가능함    
- 불변성 : s3는 Object Lock으로 worm 보장이 되는데 rds는 db 관리자가 update 한 방이면 조작 가능해서 감사 로그에는 치명적임    
- 수명 주기 : 90일 후 Glacier로, 7년 후 삭제. s3 Lifecycle 규칙 몇 줄이면 끝남    

검색은 Athena가 담당하고, s3에 있는 json을 그 자리에서 sql로 조회하고 스캔한 데이터 양만큼만 과금하는 방식

"저장은 싸게, 조회는 필요할 때만"


헷갈리는 이웃 서비스들

서비스 기록 대상 한 줄 요약
CloudTrail api 호출 누가 무엇을 했나
CloudWatch Logs 애플리케이션·시스템 로그 앱이 무슨 말을 했나
CloudWatch Metrics 성능 지표 얼마나 바쁜가
vpc Flow Logs 네트워크 트래픽 어떤 패킷이 오갔나
Config 리소스 구성 변화 지금 어떤 모습인가

saa 시험에서도 이 구분이 단골로 나오는데, "감사", "누가(who)", "규정 준수", "api 호출" 키워드가 보이면 CloudTrail이고 "구성 규칙 위반"이면 Config, "거부된 트래픽"이면 vpc Flow Logs다

cf. 그럼 EC2 안에서 rm -rf 한 것도 남을까?

안 남는다!

CloudTrail은 AWS API 경계에서 일어난 일만 보기 때문에, 인스턴스 내부에서 무슨 명령을 실행했는지, 파일 내용이 무엇이었는지는 기록하지 않는다

(이건 CloudWatch Agent나 auditd 같은 별도의 os 감사 도구의 영역)


리소스 정리

  1. EC2 인스턴스 종료(삭제)
  2. CloudTrail 추적 삭제
  1. S3 버킷 비우기 → 버킷 삭제
  2. IAM 사용자 삭제


마치며

aws 아키텍처 아이콘은 서비스 카테고리별로 색이 정해져 있다

카테고리 예시
Compute 주황 ec2, Lambda
Storage 초록 s3, ebs
Database 파랑 rds, DynamoDB
Networking 보라 vpc, CloudFront
Security, Identity 빨강 iam, GuardDuty
Management & Governance 핑크 CloudTrail, CloudWatch, CloudFormation

지난 글의 Presigned URL 자료와 비교해보면 재밌다. S3는 초록, Lambda는 주황이었으니까

여기서 흥미로운 건 CloudTrail이 보안 서비스처럼 느껴지는데도 색은 빨강(Security)이 아니라 핑크(Management & Governance)라는 점이다

사실, CloudTrail 자체는 아무것도 막지 않고 그저 기록할 뿐이며, 그 기록을 보안에 쓸지 비용 추적에 쓸지 규정 준수 증빙에 쓸지는 전부 쓰는 사람의 몫이기 때문에 핑크색이 맞는 거 같다

지난 글에서 Presigned URL이 막는 쪽이었다면 CloudTrail은 보는 쪽인데, 색깔 하나가 서비스의 성격을 정확히 말해주고 있었다는 게 신기했다!


반응형

'aws' 카테고리의 다른 글

[AWS] AWS Student Community Day 회고  (0) 2026.07.10
[AWS] S3 Presigned URL: 비공개 파일 안전하게 공유하기  (0) 2026.07.10
[AWS] DMS, Route 53, ACM  (0) 2026.07.10