Module Overview
Estimated Time: 2-3 hours | Difficulty: Intermediate | Prerequisites: IAM, S3, basic logging concepts
- CloudTrail event types and structure
- Trail configuration and multi-region setup
- CloudTrail Lake for advanced querying
- CloudTrail Insights for anomaly detection
- Security investigation workflows
How CloudTrail Works
Copy
┌─────────────────────────────────────────────────────────────────────────┐
│ CloudTrail Architecture │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ API Activity CloudTrail Destinations │
│ ──────────── ────────── ──────────── │
│ │
│ ┌──────────────┐ ┌─────────────────┐ ┌────────────────┐ │
│ │ AWS Console │─────────▶│ │────▶│ S3 Bucket │ │
│ └──────────────┘ │ │ │ (encrypted) │ │
│ │ CloudTrail │ └────────────────┘ │
│ ┌──────────────┐ │ Trail │ │
│ │ AWS CLI │─────────▶│ │ ┌────────────────┐ │
│ └──────────────┘ │ ─ Management │────▶│ CloudWatch Logs│ │
│ │ Events │ └────────────────┘ │
│ ┌──────────────┐ │ ─ Data Events │ │
│ │ AWS SDKs │─────────▶│ ─ Insights │ ┌────────────────┐ │
│ └──────────────┘ │ Events │────▶│ CloudTrail Lake│ │
│ │ │ └────────────────┘ │
│ ┌──────────────┐ └─────────────────┘ │
│ │ AWS Services │─────────▶ ┌────────────────┐ │
│ └──────────────┘ │ EventBridge │ │
│ └────────────────┘ │
│ │
│ Event Flow: │
│ ─────────── │
│ 1. User/Service makes API call │
│ 2. CloudTrail captures the event │
│ 3. Event processed and delivered (within ~15 minutes) │
│ 4. Stored in S3, queryable in Lake │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Event Types
Management Events
Operations on AWS resources (control plane):Copy
Examples:
- CreateBucket, DeleteBucket
- CreateUser, DeleteRole
- StartInstances, TerminateInstances
- CreateVpc, AttachInternetGateway
- PutBucketPolicy, PutRolePolicy
Recorded by default in all trails
Data Events
Operations on data within resources:Copy
Examples:
S3 Object-level:
- GetObject
- PutObject
- DeleteObject
Lambda Invocations:
- Invoke function calls
DynamoDB:
- GetItem, PutItem, DeleteItem
EBS Direct APIs:
- Snapshot operations
Not recorded by default (additional cost)
Insights Events
Unusual API activity detection:Copy
Detection:
- API call rate anomalies
- Error rate spikes
- Unusual patterns
Example:
- Sudden spike in DeleteObject calls
- Unusual number of failed AuthorizeSecurityGroupIngress
- High rate of DescribeInstances
Event Structure
Copy
{
"eventVersion": "1.08",
"userIdentity": {
"type": "IAMUser",
"principalId": "AIDAJ45Q7YFFAREXAMPLE",
"arn": "arn:aws:iam::123456789012:user/alice",
"accountId": "123456789012",
"accessKeyId": "AKIAIOSFODNN7EXAMPLE",
"userName": "alice",
"sessionContext": {
"sessionIssuer": {},
"webIdFederationData": {},
"attributes": {
"mfaAuthenticated": "true",
"creationDate": "2024-01-15T10:00:00Z"
}
}
},
"eventTime": "2024-01-15T10:30:00Z",
"eventSource": "s3.amazonaws.com",
"eventName": "DeleteBucket",
"awsRegion": "us-east-1",
"sourceIPAddress": "203.0.113.50",
"userAgent": "aws-cli/2.0.0 Python/3.8.0 Linux/5.4.0",
"requestParameters": {
"bucketName": "my-important-bucket"
},
"responseElements": null,
"requestID": "EXAMPLE123456789",
"eventID": "EXAMPLE-abcd-1234-5678-EXAMPLE12345",
"readOnly": false,
"resources": [
{
"accountId": "123456789012",
"type": "AWS::S3::Bucket",
"ARN": "arn:aws:s3:::my-important-bucket"
}
],
"eventType": "AwsApiCall",
"managementEvent": true,
"recipientAccountId": "123456789012",
"eventCategory": "Management"
}
Creating a Trail
Multi-Region Trail
Copy
# Create trail with all features
aws cloudtrail create-trail \
--name organization-trail \
--s3-bucket-name my-cloudtrail-bucket \
--is-multi-region-trail \
--enable-log-file-validation \
--include-global-service-events \
--kms-key-id alias/cloudtrail-key
# Start logging
aws cloudtrail start-logging --name organization-trail
# Enable data events for all S3 buckets
aws cloudtrail put-event-selectors \
--trail-name organization-trail \
--event-selectors '[{
"ReadWriteType": "All",
"IncludeManagementEvents": true,
"DataResources": [{
"Type": "AWS::S3::Object",
"Values": ["arn:aws:s3"]
}]
}]'
CloudFormation
Copy
AWSTemplateFormatVersion: '2010-09-09'
Description: Enterprise CloudTrail Configuration
Resources:
CloudTrailBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub ${AWS::AccountId}-cloudtrail-logs
VersioningConfiguration:
Status: Enabled
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: aws:kms
KMSMasterKeyID: !Ref CloudTrailKey
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
LifecycleConfiguration:
Rules:
- Id: ArchiveOldLogs
Status: Enabled
Transitions:
- StorageClass: GLACIER
TransitionInDays: 90
ExpirationInDays: 365
CloudTrailBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref CloudTrailBucket
PolicyDocument:
Version: '2012-10-17'
Statement:
- Sid: AWSCloudTrailAclCheck
Effect: Allow
Principal:
Service: cloudtrail.amazonaws.com
Action: s3:GetBucketAcl
Resource: !GetAtt CloudTrailBucket.Arn
- Sid: AWSCloudTrailWrite
Effect: Allow
Principal:
Service: cloudtrail.amazonaws.com
Action: s3:PutObject
Resource: !Sub ${CloudTrailBucket.Arn}/*
Condition:
StringEquals:
s3:x-amz-acl: bucket-owner-full-control
CloudTrailKey:
Type: AWS::KMS::Key
Properties:
Description: CloudTrail encryption key
EnableKeyRotation: true
KeyPolicy:
Version: '2012-10-17'
Statement:
- Sid: Enable Root Account
Effect: Allow
Principal:
AWS: !Sub arn:aws:iam::${AWS::AccountId}:root
Action: kms:*
Resource: '*'
- Sid: Allow CloudTrail
Effect: Allow
Principal:
Service: cloudtrail.amazonaws.com
Action:
- kms:GenerateDataKey*
- kms:DescribeKey
Resource: '*'
OrganizationTrail:
Type: AWS::CloudTrail::Trail
DependsOn: CloudTrailBucketPolicy
Properties:
TrailName: organization-trail
S3BucketName: !Ref CloudTrailBucket
IsMultiRegionTrail: true
EnableLogFileValidation: true
IncludeGlobalServiceEvents: true
IsOrganizationTrail: true
KMSKeyId: !Ref CloudTrailKey
CloudWatchLogsLogGroupArn: !GetAtt CloudTrailLogGroup.Arn
CloudWatchLogsRoleArn: !GetAtt CloudTrailRole.Arn
EventSelectors:
- ReadWriteType: All
IncludeManagementEvents: true
DataResources:
- Type: AWS::S3::Object
Values:
- arn:aws:s3
- Type: AWS::Lambda::Function
Values:
- arn:aws:lambda
InsightSelectors:
- InsightType: ApiCallRateInsight
- InsightType: ApiErrorRateInsight
CloudTrailLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: /aws/cloudtrail/organization
RetentionInDays: 90
CloudTrailRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: cloudtrail.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: CloudTrailLogsPolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- logs:CreateLogStream
- logs:PutLogEvents
Resource: !GetAtt CloudTrailLogGroup.Arn
CloudTrail Lake
Create Event Data Store
Copy
# Create event data store for 1 year retention
aws cloudtrail create-event-data-store \
--name security-events \
--retention-period 365 \
--multi-region-enabled \
--organization-enabled
# Get event data store ID
aws cloudtrail list-event-data-stores
Query with SQL
Copy
-- Find all DeleteBucket events
SELECT
eventTime,
userIdentity.userName,
sourceIPAddress,
requestParameters.bucketName
FROM security-events
WHERE eventName = 'DeleteBucket'
AND eventTime > '2024-01-01 00:00:00'
ORDER BY eventTime DESC
LIMIT 100;
-- Find failed console logins
SELECT
eventTime,
userIdentity.userName,
sourceIPAddress,
errorCode,
errorMessage
FROM security-events
WHERE eventName = 'ConsoleLogin'
AND errorCode IS NOT NULL
AND eventTime > '2024-01-01 00:00:00'
ORDER BY eventTime DESC;
-- Find root account activity
SELECT
eventTime,
eventName,
sourceIPAddress,
userAgent
FROM security-events
WHERE userIdentity.type = 'Root'
AND eventTime > '2024-01-01 00:00:00'
ORDER BY eventTime DESC;
-- Find security group modifications
SELECT
eventTime,
userIdentity.userName,
eventName,
requestParameters
FROM security-events
WHERE eventName LIKE '%SecurityGroup%'
AND eventTime > '2024-01-01 00:00:00'
ORDER BY eventTime DESC;
-- Find IAM policy changes
SELECT
eventTime,
userIdentity.userName,
eventName,
requestParameters.policyArn
FROM security-events
WHERE eventName LIKE '%Policy%'
AND eventSource = 'iam.amazonaws.com'
AND eventTime > '2024-01-01 00:00:00';
CloudTrail Insights
Enable Insights
Copy
# Enable insights on existing trail
aws cloudtrail put-insight-selectors \
--trail-name organization-trail \
--insight-selectors '[
{"InsightType": "ApiCallRateInsight"},
{"InsightType": "ApiErrorRateInsight"}
]'
Insights Event Example
Copy
{
"eventVersion": "1.08",
"eventTime": "2024-01-15T10:30:00Z",
"eventSource": "cloudtrail.amazonaws.com",
"eventName": "DeleteObject",
"eventCategory": "Insight",
"insightDetails": {
"state": "Start",
"eventSource": "s3.amazonaws.com",
"eventName": "DeleteObject",
"insightType": "ApiCallRateInsight",
"insightContext": {
"statistics": {
"baseline": {
"average": 10.5
},
"insight": {
"average": 500.2
}
}
}
}
}
Security Monitoring
CloudWatch Alarms
Copy
# Metric filter for root account usage
Resources:
RootAccountUsageFilter:
Type: AWS::Logs::MetricFilter
Properties:
LogGroupName: /aws/cloudtrail/organization
FilterPattern: '{ $.userIdentity.type = "Root" && $.userIdentity.invokedBy NOT EXISTS && $.eventType != "AwsServiceEvent" }'
MetricTransformations:
- MetricName: RootAccountUsage
MetricNamespace: CloudTrail
MetricValue: '1'
RootAccountUsageAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmName: RootAccountUsage
AlarmDescription: Root account was used
MetricName: RootAccountUsage
Namespace: CloudTrail
Statistic: Sum
Period: 300
EvaluationPeriods: 1
Threshold: 1
ComparisonOperator: GreaterThanOrEqualToThreshold
AlarmActions:
- !Ref SecurityAlertsTopic
# Unauthorized API calls
UnauthorizedAPICallsFilter:
Type: AWS::Logs::MetricFilter
Properties:
LogGroupName: /aws/cloudtrail/organization
FilterPattern: '{ ($.errorCode = "*UnauthorizedAccess*") || ($.errorCode = "AccessDenied*") }'
MetricTransformations:
- MetricName: UnauthorizedAPICalls
MetricNamespace: CloudTrail
MetricValue: '1'
# Console login without MFA
NoMFALoginFilter:
Type: AWS::Logs::MetricFilter
Properties:
LogGroupName: /aws/cloudtrail/organization
FilterPattern: '{ ($.eventName = "ConsoleLogin") && ($.additionalEventData.MFAUsed != "Yes") }'
MetricTransformations:
- MetricName: ConsoleLoginWithoutMFA
MetricNamespace: CloudTrail
MetricValue: '1'
# IAM policy changes
IAMPolicyChangesFilter:
Type: AWS::Logs::MetricFilter
Properties:
LogGroupName: /aws/cloudtrail/organization
FilterPattern: '{ ($.eventName=DeleteGroupPolicy) || ($.eventName=DeleteRolePolicy) || ($.eventName=DeleteUserPolicy) || ($.eventName=PutGroupPolicy) || ($.eventName=PutRolePolicy) || ($.eventName=PutUserPolicy) || ($.eventName=CreatePolicy) || ($.eventName=DeletePolicy) || ($.eventName=CreatePolicyVersion) || ($.eventName=DeletePolicyVersion) || ($.eventName=AttachRolePolicy) || ($.eventName=DetachRolePolicy) || ($.eventName=AttachUserPolicy) || ($.eventName=DetachUserPolicy) || ($.eventName=AttachGroupPolicy) || ($.eventName=DetachGroupPolicy) }'
MetricTransformations:
- MetricName: IAMPolicyChanges
MetricNamespace: CloudTrail
MetricValue: '1'
EventBridge Rules
Copy
Resources:
# Alert on security group changes
SecurityGroupChangeRule:
Type: AWS::Events::Rule
Properties:
Name: security-group-changes
EventPattern:
source:
- aws.ec2
detail-type:
- AWS API Call via CloudTrail
detail:
eventSource:
- ec2.amazonaws.com
eventName:
- AuthorizeSecurityGroupIngress
- AuthorizeSecurityGroupEgress
- RevokeSecurityGroupIngress
- RevokeSecurityGroupEgress
- CreateSecurityGroup
- DeleteSecurityGroup
Targets:
- Arn: !Ref SecurityAlertsTopic
Id: SNSTarget
Investigation Workflow
Copy
┌─────────────────────────────────────────────────────────────────────────┐
│ Security Investigation Workflow │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ 1. Alert Received │
│ ───────────────── │
│ ─ GuardDuty finding │
│ ─ Security Hub alert │
│ ─ CloudWatch alarm │
│ │
│ 2. Initial Triage │
│ ───────────────── │
│ Query CloudTrail Lake: │
│ ─ Who: userIdentity (user/role/service) │
│ ─ What: eventName, requestParameters │
│ ─ When: eventTime │
│ ─ Where: sourceIPAddress, awsRegion │
│ │
│ 3. Timeline Analysis │
│ ────────────────── │
│ ─ Events before/after incident │
│ ─ Related API calls from same identity │
│ ─ Same source IP activity │
│ │
│ 4. Scope Assessment │
│ ────────────────── │
│ ─ Which resources were accessed? │
│ ─ What data was potentially exposed? │
│ ─ Are other accounts affected? │
│ │
│ 5. Containment │
│ ───────────── │
│ ─ Disable compromised credentials │
│ ─ Revoke sessions │
│ ─ Isolate affected resources │
│ │
│ 6. Document & Report │
│ ─────────────────── │
│ ─ Export relevant CloudTrail events │
│ ─ Create incident report │
│ ─ Update runbooks │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Best Practices
Enable Multi-Region
Attackers may target regions you don’t actively use
Log Validation
Enable log file integrity validation for forensics
Use Lake
CloudTrail Lake enables SQL queries without S3/Athena setup
Enable Insights
Detect unusual API activity patterns automatically
Security Checklist
Copy
Logging Configuration:
✓ Multi-region trail enabled
✓ Global service events included
✓ Log file validation enabled
✓ S3 bucket encrypted with KMS
✓ Data events for sensitive S3 buckets
✓ Lambda invocation logging
✓ CloudTrail Insights enabled
Monitoring:
✓ CloudWatch alarms for critical events
✓ EventBridge rules for real-time alerts
✓ Root account usage monitoring
✓ Failed authentication tracking
Retention:
✓ S3 lifecycle policies configured
✓ CloudTrail Lake for long-term analysis
✓ Compliance requirements met
🎯 Interview Questions
Q1: What's the difference between management events and data events?
Q1: What's the difference between management events and data events?
Management Events (Control Plane):
- Operations on AWS resources
- CreateBucket, DeleteUser, StartInstances
- Logged by default
- Lower volume
- Operations on data within resources
- GetObject, PutObject, Invoke
- Not logged by default (extra cost)
- High volume
Q2: How would you investigate a potential security breach using CloudTrail?
Q2: How would you investigate a potential security breach using CloudTrail?
- Identify compromised credentials: Find the access key or role
- Timeline analysis: Query all events from that identity
- Source IP analysis: Check for unusual IPs or geolocations
- Resource access: Identify what was accessed/modified
- Lateral movement: Check for AssumeRole or CreateAccessKey
- Scope assessment: Determine if other accounts affected
Q3: How do you ensure CloudTrail log integrity?
Q3: How do you ensure CloudTrail log integrity?
- Enable log file validation: Creates digest files with hashes
- KMS encryption: Encrypt logs at rest
- S3 bucket policy: Prevent deletion/modification
- Object Lock: Enable S3 Object Lock for immutability
- Cross-account: Store logs in separate security account
- MFA Delete: Require MFA for log deletion
Hands-On Lab
1
Create Organization Trail
Set up multi-region trail with encryption and validation
2
Enable Data Events
Configure S3 and Lambda data event logging
3
Set Up CloudTrail Lake
Create event data store and run sample queries
4
Create Alarms
Set up CloudWatch alarms for root account usage
5
Investigate
Use CloudTrail Lake to investigate a simulated incident
Next Module
AWS Config
Configuration compliance and change management