Tìm Kẻ Đã Xóa EC2 Instance Bằng CloudTrail Event History
Một EC2 instance biến mất khỏi console mà không có cảnh báo nào — đây là tình huống thực tế mà nhiều team vận hành đã gặp phải. Câu hỏi đầu tiên luôn là: ai đã chạy TerminateInstances, và khi nào? Bài viết này hướng dẫn cách dùng CloudTrail Event History để truy vết hành động xóa EC2 instance, từ console đến CLI, kèm phân tích log thực tế.
TL;DR — Tóm Tắt Nhanh
| Bước | Hành động | Mục tiêu |
|---|---|---|
| 1 | Mở CloudTrail Event History | Tìm sự kiện TerminateInstances |
| 2 | Lọc theo tên sự kiện hoặc Instance ID | Thu hẹp kết quả về đúng tài nguyên |
| 3 | Đọc trường userIdentity | Xác định IAM user, role, hoặc assumed role |
| 4 | Kiểm tra sourceIPAddress và userAgent | Xác định nguồn gốc hành động (console, CLI, SDK) |
| 5 | Dùng S3/Athena nếu sự kiện ngoài 90 ngày | Truy vết lịch sử dài hơn |
CloudTrail Event History Hoạt Động Như Thế Nào
CloudTrail ghi lại các API call được thực hiện trong tài khoản AWS của bạn. Mỗi khi một EC2 instance bị terminate, dịch vụ EC2 ghi nhận một management event tên TerminateInstances vào CloudTrail. Event History là giao diện tìm kiếm nhanh cho 90 ngày gần nhất — không cần cấu hình trail riêng, AWS tự động lưu management events ở cấp region.
Hãy nghĩ CloudTrail Event History như camera an ninh tự động ghi lại mọi thao tác API trong 90 ngày. Bạn không cần cài đặt gì — chỉ cần biết cách tua lại đúng thời điểm.
Điều quan trọng cần hiểu: Event History chỉ lưu management events (control plane), không lưu data events như S3 GetObject hay Lambda invocation theo mặc định. Với EC2 terminate, đây là management event nên luôn được ghi lại.
(User / Role / Service)"] -->|"API: TerminateInstances"| B["EC2 API"] B -->|"Trạng thái: shutting-down"| C["EC2 Instance"] B -->|"Management Event"| D["CloudTrail"] D --> E["Event History
(90 ngày)"] D -->|"Nếu có trail"| F["S3 Bucket
(Lưu trữ dài hạn)"] G["Investigator"] -->|"lookup-events / Console"| E G -->|"Athena Query"| F
- IAM Principal (user, role, hoặc service) gọi API
TerminateInstancesđến EC2. - EC2 API xử lý yêu cầu và thay đổi trạng thái instance sang
shutting-downrồiterminated. - CloudTrail nhận management event và ghi vào Event History (region-level, tự động).
- Nếu có trail được cấu hình, event cũng được gửi đến S3 bucket để lưu trữ dài hạn.
- Investigator truy vấn Event History qua console hoặc CLI để tìm thông tin
userIdentity.
Truy Vết TerminateInstances Qua CloudTrail Event History
Bước đầu tiên là xác định chính xác sự kiện terminate. Event History cho phép lọc theo nhiều thuộc tính — cách hiệu quả nhất là kết hợp tên sự kiện với resource name để loại bỏ nhiễu ngay từ đầu.
Cách 1: Tìm Qua AWS Console
- Truy cập AWS CloudTrail Console → chọn Event History ở menu trái.
- Trong dropdown Lookup attributes, chọn Event name.
- Nhập
TerminateInstancesvào ô tìm kiếm. - Điều chỉnh khoảng thời gian phù hợp với thời điểm instance biến mất.
- Click vào sự kiện để xem chi tiết JSON — tập trung vào các trường
userIdentity,sourceIPAddress,requestParameters.
Nếu có nhiều kết quả (môi trường có nhiều terminate hợp lệ), chuyển sang lọc theo Resource name với Instance ID cụ thể để thu hẹp ngay.
Cách 2: Dùng AWS CLI — Nhanh Và Có Thể Tự Động Hóa
CLI cho phép lọc kết quả và parse JSON trực tiếp, phù hợp khi cần điều tra nhanh hoặc tích hợp vào runbook. Lưu ý: lookup-events chỉ hỗ trợ một lookup attribute duy nhất trong mỗi lần gọi — không thể kết hợp nhiều --lookup-attributes trong cùng một lệnh. Để lọc theo cả tên sự kiện lẫn resource, hãy dùng jq để post-filter kết quả.
Bước 1: Tìm theo tên sự kiện
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=EventName,AttributeValue=TerminateInstances \
--start-time 2024-01-15T00:00:00Z \
--end-time 2024-01-16T23:59:59Z \
--region us-east-1 \
--output json
Bước 2: Lọc theo Instance ID cụ thể
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=ResourceName,AttributeValue=i-0abcd1234efgh5678 \
--start-time 2024-01-15T00:00:00Z \
--end-time 2024-01-16T23:59:59Z \
--region us-east-1 \
--output json
Bước 3: Parse kết quả để lấy thông tin người thực hiện
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=EventName,AttributeValue=TerminateInstances \
--start-time 2024-01-15T00:00:00Z \
--end-time 2024-01-16T23:59:59Z \
--region us-east-1 \
--output json | jq '.Events[] | {
eventTime: .EventTime,
user: .Username,
sourceIP: (.CloudTrailEvent | fromjson | .sourceIPAddress),
userAgent: (.CloudTrailEvent | fromjson | .userAgent),
userIdentity: (.CloudTrailEvent | fromjson | .userIdentity),
instances: (.CloudTrailEvent | fromjson | .requestParameters.instancesSet.items)
}'
Đọc Hiểu CloudTrail Event — Phần Quan Trọng Nhất
Tìm được sự kiện chỉ là bước đầu. Phần giá trị thực sự nằm ở việc đọc đúng các trường trong JSON event. Đây là nơi nhiều người bỏ sót thông tin quan trọng.
.instancesSet"] B --> B1["type: IAMUser / AssumedRole / Root"] B --> B2["arn: ARN đầy đủ của principal"] B --> B3["sessionContext
(nếu AssumedRole)"] B3 --> B4["sessionIssuer.arn
→ Role gốc"] B3 --> B5["mfaAuthenticated"] C --> C1["aws-internal = AWS Service
IP thực = User / CLI"] D --> D1["console.amazonaws.com
aws-cli / SDK"] E --> E1["Danh sách Instance ID
bị terminate"]
- userIdentity.type: Cho biết loại principal —
IAMUser,AssumedRole,Root, hoặcAWSService. - userIdentity.arn: ARN đầy đủ của principal thực hiện hành động.
- userIdentity.sessionContext: Nếu type là
AssumedRole, trường này chứa thông tin role session, bao gồmsessionIssuercho biết role gốc. - sourceIPAddress: IP nguồn —
aws-internalnghĩa là hành động từ AWS service, không phải người dùng trực tiếp. - userAgent: Cho biết công cụ được dùng —
console.amazonaws.com,aws-cli, hoặc SDK cụ thể. - requestParameters.instancesSet: Danh sách Instance ID bị terminate trong lần gọi này.
Ví Dụ Event JSON Thực Tế
🔽 Click để xem ví dụ CloudTrail event JSON đầy đủ
{
"eventVersion": "1.08",
"userIdentity": {
"type": "AssumedRole",
"principalId": "AROAEXAMPLEID:session-name",
"arn": "arn:aws:sts::123456789012:assumed-role/DevOpsRole/session-name",
"accountId": "123456789012",
"sessionContext": {
"sessionIssuer": {
"type": "Role",
"principalId": "AROAEXAMPLEID",
"arn": "arn:aws:iam::123456789012:role/DevOpsRole",
"accountId": "123456789012",
"userName": "DevOpsRole"
},
"webIdFederationData": {},
"attributes": {
"creationDate": "2024-01-15T10:30:00Z",
"mfaAuthenticated": "false"
}
}
},
"eventTime": "2024-01-15T14:23:45Z",
"eventSource": "ec2.amazonaws.com",
"eventName": "TerminateInstances",
"awsRegion": "us-east-1",
"sourceIPAddress": "203.0.113.42",
"userAgent": "aws-cli/2.13.0 Python/3.11.0",
"requestParameters": {
"instancesSet": {
"items": [
{"instanceId": "i-0abcd1234efgh5678"}
]
}
},
"responseElements": {
"instancesSet": {
"items": [
{
"instanceId": "i-0abcd1234efgh5678",
"currentState": {"code": 32, "name": "shutting-down"},
"previousState": {"code": 16, "name": "running"}
}
]
}
}
}
Trong ví dụ này, hành động được thực hiện bởi DevOpsRole qua AWS CLI từ IP 203.0.113.42. Trường mfaAuthenticated: false là thông tin đáng chú ý nếu policy yêu cầu MFA cho các hành động destructive.
Tình Huống Thực Tế: Sai Lầm Chẩn Đoán Phổ Biến
Một team nhận được báo cáo instance bị xóa lúc 2 giờ sáng. Họ kiểm tra IAM user của developer trực ca và không tìm thấy gì. Kết luận ban đầu: có thể là lỗi hệ thống hoặc Auto Scaling.
Thực tế khi đọc kỹ trường userIdentity: type là AssumedRole, và sessionIssuer.arn trỏ đến một Lambda execution role — không phải người dùng trực tiếp. Lambda function đó có logic cleanup tự động đang chạy theo schedule, và điều kiện lọc instance bị viết sai, khiến nó terminate nhầm instance production.
Bài học: khi userIdentity.type là AssumedRole, đừng dừng lại ở ARN session — luôn kiểm tra sessionContext.sessionIssuer để tìm role gốc, sau đó tìm xem service nào đang assume role đó.
sourceIPAddress là 'aws-internal' không có nghĩa là không truy vết được — nó có nghĩa là một AWS service đã thực hiện hành động thay mặt một principal. Tìm tiếp trong sessionContext.
IAM Policy Tối Thiểu Để Điều Tra CloudTrail
Người điều tra cần quyền đọc CloudTrail nhưng không cần quyền ghi hay quản lý trail. Policy sau áp dụng nguyên tắc least privilege cho tác vụ điều tra sự kiện:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "CloudTrailReadForInvestigation",
"Effect": "Allow",
"Action": [
"cloudtrail:LookupEvents",
"cloudtrail:GetTrailStatus",
"cloudtrail:DescribeTrails"
],
"Resource": "*"
}
]
}
Lưu ý: cloudtrail:LookupEvents không hỗ trợ resource-level restriction — Resource: "*" là bắt buộc theo AWS Service Authorization Reference. Đây là hành vi đã được tài liệu hóa, không phải lỗi cấu hình.
Khi Event History Không Đủ — Vượt Quá 90 Ngày
Event History chỉ lưu 90 ngày. Nếu sự kiện xảy ra trước đó, bạn cần trail được cấu hình gửi log đến S3. Kiểm tra trail hiện tại:
aws cloudtrail describe-trails \
--region us-east-1 \
--output json
aws cloudtrail get-trail-status \
--name your-trail-name \
--region us-east-1 \
--output json
Nếu trail đang active và ghi vào S3, bạn có thể dùng Amazon Athena để query trực tiếp trên CloudTrail log files trong S3 — hiệu quả hơn nhiều so với download và parse thủ công khi volume log lớn.
90 ngày gần nhất?"} B -->|"Có"| C["CloudTrail Event History
(Console hoặc CLI)"] B -->|"Không"| D{"Có CloudTrail Trail
ghi vào S3?"} D -->|"Có"| E["Query S3 logs
bằng Amazon Athena"] D -->|"Không"| F["Không thể khôi phục
→ Cần cấu hình trail ngay"] C --> G["Đọc userIdentity
và sessionContext"] E --> G G --> H["Xác định principal
thực hiện hành động"]
- 90 ngày trở lại: Dùng Event History trực tiếp — nhanh nhất, không cần cấu hình thêm.
- Hơn 90 ngày, có trail: Query CloudTrail logs trong S3 bằng Athena.
- Hơn 90 ngày, không có trail: Không thể khôi phục lịch sử — đây là lý do cần cấu hình trail với S3 từ đầu.
Kết Luận Và Bước Tiếp Theo
Truy vết CloudTrail TerminateInstances không phức tạp nếu biết đọc đúng trường trong event JSON. Điểm mấu chốt là không dừng lại ở Username — luôn kiểm tra userIdentity.type và sessionContext để hiểu toàn bộ chuỗi ủy quyền.
Để tránh lặp lại tình huống tương tự, cân nhắc:
- Cấu hình CloudTrail trail với S3 để lưu log vượt quá 90 ngày.
- Tạo CloudWatch Alarm hoặc EventBridge rule để cảnh báo real-time khi có
TerminateInstancesxảy ra ngoài giờ hành chính. - Bật EC2 termination protection cho các instance production quan trọng.
- Review IAM policy định kỳ — đặc biệt các role có quyền
ec2:TerminateInstances.
Tham khảo thêm: AWS CloudTrail Event History Documentation và CloudTrail Log File Examples.
Glossary — Thuật Ngữ Chính
| Thuật ngữ | Giải thích |
|---|---|
| Management Event | API call tác động đến cấu hình tài nguyên AWS (tạo, xóa, sửa) — được CloudTrail ghi lại mặc định. |
| userIdentity | Trường trong CloudTrail event chứa thông tin đầy đủ về principal thực hiện hành động. |
| AssumedRole | Loại principal khi một entity (user, service, Lambda) assume một IAM role để thực hiện hành động. |
| sessionContext | Metadata của role session, bao gồm role gốc (sessionIssuer) và thời điểm tạo session. |
| Event History | Giao diện tìm kiếm CloudTrail cho 90 ngày gần nhất, không cần cấu hình trail riêng. |
Nhận xét
Đăng nhận xét