Post

[AWS-Security] 8.2. 관리 이벤트 기록

[AWS-Security] 8.2. 관리 이벤트 기록

1. 관리 이벤트

보안 문제가 발생했을 때 가장 먼저 찾아봐야 할 정보 소스는 리소스 관리 이벤트(Management Event)이다.
이는 AWS API 호출이나 관리 콘솔에서 수행되는 “리소스 생성, 수정, 삭제하는 모든 작업”을 뜻한다. 이 정보를 로깅하는 기본 도구가 바로 AWS CloudTrail이다.

관리 이벤트(Management Event) vs 데이터 이벤트(Data Event)
CloudTrail이 모든 것을 다 기록하는 것은 아니다.

  • 관리 이벤트 (기본 기록 됨) : 인프라의 구성을 바꾸는 작업이다.
    (ex. DynamoDB 테이블 생성/삭제, S3 버킷 생성, EC2 인스턴스 시작, SQS 큐 생성 등)
  • 데이터 이벤트 (기본 기록 안됨) : 리소스 ‘내부’의 데이터를 읽고 쓰는 대량의 작업이다.
    (ex. DynamoDB 테이블의 레코드 읽기/쓰기, S3 객체 다운로드(GetObject), Lambda 함수 호출(Invoke), SQS 메시지 전송 등)

2. CloudTrail 설정

AWS 계정을 생성하면 CloudTrail은 기본적으로 활성화되어 최신 90일간의 관리 이벤트를 ‘이벤트 기록(Event History)’에 보관한다. 하지만 90일이 지난 과거의 기록을 영구적으로 보존하려면, 로그를 지정된 S3 버킷에 계속해서 저장해 주는 새로운 추적(Trail)을 명시적으로 생성해야 한다.

2.1. 로그를 저장할 S3 버킷 및 추적(Trail) 생성

1
2
3
4
5
6
7
# 로그를 저장할 신규 CloudTrail 추적 및 S3 버킷 생성

# 1. 로그를 보관할 고유한 이름의 S3 버킷 생성
$ aws s3api create-bucket --bucket my-cloudtrail-bucket

# 2. 모든 리전의 이벤트를 해당 S3 버킷으로 보내는 추적(Trail) 생성
$ aws cloudtrail create-trail --name MyTrail --s3-bucket-name my-cloudtrail-bucket

2.2. 추적(Trail) 생성 확인

1
2
# describe-trails를 호출해 신규 추적이 생성됐는지 확인
$ aws cloudtrail describe-trails
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* describe-trails 호출의 출력 (JSON) */
{
  "trailList": [{
    "Name": "MyTrail",
    "S3BucketName": "my-cloudtrail-bucket",
    "IncludeGlobalServiceEvents": true,
    "IsMultiRegionTrail": true,
    "HomeRegion": "us-east-1",
    "TrailARN": "arn:aws:cloudtrail:us-east-1:123456789012:trail/MyTrail",
    "LogFileValidationEnabled": true,
    "HasCustomEventSelectors": false,
    "IsOrganizationTrail": false
  }]
}
  • IncludeGlobalServiceEvent : IAM 이벤트와 같은 글로벌(비리전) 이벤트도 기록할지 여부 (true)
  • IsMultiRegionTrail : 현재 리전뿐만 아니라 모든 리전의 이벤트를 기록할지 여부 (true)

3. CloudTrail 로그 검색 및 필터링

로그가 쌓이기 시작하면, 의심스러운 활동을 찾아내기 위해 로그를 검색(쿼리)해야 한다.

3.1. 기본 최근 이벤트 조최

1
2
# lookup-events 메서드를 사용해 CloudTrail에서 로그 검색
$ aws cloudtrail lookup-events
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* CloudTrail lookup-events 호출의 샘플 출력 이벤트 */
{
  "Events": [{
    "EventId": "298fc38a-456d-4645-a550-427a535ce346",
    "EventName": "TerminateInstances",
    "ReadOnly": "false",
    "AccessKeyId": "AKIAEXAMPLE",
    "EventTime": 1604090694.0,
    "EventSource": "ec2.amazonaws.com",
    "Username": "Dylan",
    "Resources": ["..."],
    "CloudTrailEvent": "{ ... }"
  }]
}
  • Dylan이라는 사용자(Username)가 EC2 서비스(EventSource)에서 인스턴스 종료(TerminateInstances) 작업을 수행했음을 알 수 있다.

3.2. 특정 속성으로 필터링하여 검색 (해커 추적 시나리오)

모든 이벤트를 보는 것은 비효율적이다. 특정 사용자(ex. ‘Dylan’ 계정이 탈취된 것으로 의심될 때)의 행위만 걸러서 볼 수 있다. AWS CLI에서는 Usernaem, EventName, EventId, ResourceType 등의 기준으로 필터링이 가능하다.

1
2
3
4
# 조회 속성으로 CloudTrail 로그 필터링
# 사용자 이름(Username)이 'Dylan'인 결과만 필터링하여 조회
$ aws cloudtrail lookup-events \
    --lookup-attributes AttributeKey=Username,AttributeValue=Dylan
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* 필터링된 조회 이벤트 호출의 샘플 이벤트 레코드 */
{
  "Events": [{
    "EventId": "298fc38a-456d-4645-a550-427a535ce346",
    "EventName": "TerminateInstances",
    "ReadOnly": "false",
    "AccessKeyId": "AKIAEXAMPLE",
    "EventTime": 1604090694.0,
    "EventSource": "ec2.amazonaws.com",
    "Username": "Dylan",
    "Resources": ["..."],
    "CloudTrailEvent": "{ ... }"
  }]
}
  • 콘솔 활용 : CLI가 익숙하지 않다면 AWS Management Console의 CloudTrail -> Event history 탭에서도 동일하게 확인할 수 있다.

4. CloudTrail 로그를 통한 이슈 조사 (실전 시나리오)

4.1. 사건 발생

  • 상황 : 평소 한 달에 약 250달러(약 30만원) 정도의 EC2 비용만 나오던 애플리케이션이다.
  • 이상 징후 : 어느 날 AWS Billing 콘솔을 확인해 보니, 이번 달 EC2 청구 금액이 무료 9,000달러 이상으로 폭증했다.
  • 초기 확인 : EC2 대시보드를 확인했지만, 현재 실행 중인 인스턴스는 평소에 쓰던 것 하나뿐이다.
  • 가설 수립 : 관리자의 실수로 여분의 인스턴스를 띄워둔 것일 수도 있고, 최악의 경우 공격자가 IAM 자격 증명을 탈취해 암호화폐 채굴이나 봇넷(Botnet)을 위해 몰래 고사용 인스터스를 실행 했을 수도 있다.

4.2. 1단계: CloudTrail에서 EC2 생성 이벤트 필터링

거액의 요금이 발생했다면, 분명 누군가 EC2 리소스를 대량으로 생성했을 것이다. EC2 인스턴스 생성은 ‘관리 이벤트’이므로 CloudTrail을 통해 확인할 수 있다.

  • lookup-events 명령어나 콘솔을 사용하여, 이벤트 소스(Event Source)를 ec2.amazonaws.com으로 좁히고 이벤트를 검색한다.

4.3. 2단계: 비정상적인 패턴 발견

검색된 이벤트 목록을 보면 매우 이상한 패턴이 있다.

  • 수상한 시간대 : 10월 24일부터 27일까지 매일 밤늦은 시간(21:30)에 인스턴스 시작(RunInstance)되고, 새벽 시간(04:30)에 종료(TerminateInstances)되는 작업이 반복되었다.
  • 작업자 : 수상한 작업을 수행한 사용자는 IAM 사용자 ‘Dylan’이다.

4.4. 3단계: 상세 로그 분석으로 원인 규명

단순히 인스턴스를 켰다 끈 것만으로는 9,000달러라는 비용은 너무 많다. 어떤 종류의 인스턴스를 실행했는지 알아보기 위해 해당 RunInstances 이벤트의 전체 JSON 레코드를 확인한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
{
  "eventVersion": "1.05",
  "userIdentity": {
    "type": "AssumedRole",
    "principalId": "AROAEXAMPLE:Dylan",
    "arn": "arn:aws:sts::123456789012:assumed-role/Admin/Dylan",
    "accountId": "123456789012",
    "accessKeyId": "ASIAEXAMPLE"
  },
  "eventTime": "2020-11-16T10:33:45Z",
  "eventSource": "ec2.amazonaws.com",
  "eventName": "RunInstances",
  "awsRegion": "us-east-1",
  "sourceIPAddress": "192.168.0.1",
  "userAgent": "console.ec2.amazonaws.com",
  "eventID": "8e688a17-3c5e-4292-a762-3134bebaf9a8",
  "eventType": "AwsApiCall",
  "requestParameters": {
    "instancesSet": {
      "items": [
        {
          "imageId": "ami-0947d2ba12ee1ff75",
          "minCount": 1,
          "maxCount": 1,
          "keyName": "Test"
        }
      ]
    },
    "instanceType": "p3.16xl"
  },
  "responseElements": {
    "instancesSet": {
      "items": [
        {
          "instanceId": "i-a1b2c3",
          "imageId": "ami-0947d2ba12ee1ff75",
          "instanceType": "p3.16xl"
        }
      ]
    }
  }
}
  • userIdentity : 이벤트를 실행한 주체가 누구인지 알려준다. (IAM 사용자 ‘Dylan’의 권한 사용)
  • eventSource & eventName : 어떤 서비스에서 무슨 API를 호출했는지 알려준다. (EC2의 RunInstance 호출)
  • requestParameters : 이벤트 호출 시 전달된 매개변수이다. 여기에 사건의 핵심 원인이 있다. instanceType이 p3.16xl로 지정되어 있다. (p3.16xlarge는 무거운 머신러닝이나 HPC에 사용되는 초고사양의 인스턴스이다.)
  • responseElements : AWS가 이벤트 요청을 받고 반환한 응답 결과이다. i-a1b2c3라는 ID를 가진 p3.16xl 인스턴스가 성공적으로 시작되었음을 알 수 있다.

4.5. 결론 도출 및 후속 조치

  • 결론 : 관리자인 나는 위와 같은 작업을 진행한 적이 없다. 즉, 이것은 관리자의 단순 구성 오류가 아니라 공격자(해커)가 ‘Dylan’의 IAM 자격 증명(Access Key)을 탈취하여 불법으로 리소스를 사용한 보안 침해(해킹) 사고임을 확신할 수 있다.
  • 조치 사항 : 파악한 즉시 영향을 받은 IAM 사용자의 자격 증명을 무효화/변경하고, 남아있는 악성 리소스를 삭제한 뒤 AWS Support 팀에 문의하여 상황을 수습해야 한다.
This post is licensed under CC BY 4.0 by the author.