AWS CloudTrail provides comprehensive audit logging of all API activity in your AWS account. Every action taken in the console, CLI, SDK, or by AWS services is recorded, creating an essential security and compliance tool. This guide covers setting up CloudTrail with best practices for production environments.
This article is part of our comprehensive Cloud Security Tips for 2026 guide covering essential practices for protecting your cloud environment.
Why CloudTrail is Essential
CloudTrail enables you to:
- Security Analysis - Detect unauthorized access and suspicious activity
- Compliance Auditing - Meet regulatory requirements (SOC 2, HIPAA, PCI DSS)
- Operational Troubleshooting - Trace issues back to specific API calls
- Change Tracking - Know who changed what and when
Create a Multi-Region Trail
A multi-region trail captures activity across all AWS regions, ensuring no activity is missed.
Step 1: Navigate to CloudTrail Console
- Open the CloudTrail Console
- Click Create trail
Step 2: Configure Trail Attributes
- Enter a trail name (e.g., "organization-audit-trail")
- Enable Enable for all accounts in my organization (if using AWS Organizations)
- Select Create new S3 bucket or use an existing bucket
- Enable Log file SSE-KMS encryption for enhanced security
- Enable Log file validation to detect tampering
Step 3: Choose Log Events
For comprehensive logging:
- Management events: Read and Write (captures all control plane activity)
- Data events: Enable for critical S3 buckets and Lambda functions
- Insights events: Enable to detect unusual API activity patterns
Step 4: Review and Create
- Review all settings
- Click Create trail
Create Trail Using AWS CLI
For automation and infrastructure-as-code workflows:
# Create S3 bucket for logs
aws s3api create-bucket \
--bucket my-cloudtrail-logs-123456789012 \
--region us-east-1
# Apply bucket policy for CloudTrail
aws s3api put-bucket-policy \
--bucket my-cloudtrail-logs-123456789012 \
--policy file://cloudtrail-bucket-policy.json
# Create multi-region trail
aws cloudtrail create-trail \
--name organization-audit-trail \
--s3-bucket-name my-cloudtrail-logs-123456789012 \
--is-multi-region-trail \
--enable-log-file-validation \
--include-global-service-events
# Start logging
aws cloudtrail start-logging \
--name organization-audit-trailS3 Bucket Policy for CloudTrail
Create cloudtrail-bucket-policy.json:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AWSCloudTrailAclCheck",
"Effect": "Allow",
"Principal": {
"Service": "cloudtrail.amazonaws.com"
},
"Action": "s3:GetBucketAcl",
"Resource": "arn:aws:s3:::my-cloudtrail-logs-123456789012"
},
{
"Sid": "AWSCloudTrailWrite",
"Effect": "Allow",
"Principal": {
"Service": "cloudtrail.amazonaws.com"
},
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::my-cloudtrail-logs-123456789012/AWSLogs/*",
"Condition": {
"StringEquals": {
"s3:x-amz-acl": "bucket-owner-full-control"
}
}
}
]
}Configure Log File Validation
Log file validation ensures logs haven't been tampered with:
# Enable log file validation on existing trail
aws cloudtrail update-trail \
--name organization-audit-trail \
--enable-log-file-validation
# Validate log file integrity
aws cloudtrail validate-logs \
--trail-arn arn:aws:cloudtrail:us-east-1:123456789012:trail/organization-audit-trail \
--start-time 2026-01-01T00:00:00Z \
--end-time 2026-01-13T23:59:59ZCloudTrail creates digest files every hour that contain hashes of log files, enabling detection of any modifications.
Enable CloudTrail Insights
CloudTrail Insights automatically detects unusual API activity:
# Enable Insights on a trail
aws cloudtrail put-insight-selectors \
--trail-name organization-audit-trail \
--insight-selectors '[{"InsightType": "ApiCallRateInsight"}, {"InsightType": "ApiErrorRateInsight"}]'Insights can detect:
- Unusual spikes in API call volume
- Elevated error rates indicating potential attacks
- Anomalous write management events
Send Logs to CloudWatch
Integrate with CloudWatch Logs for real-time monitoring:
# Create CloudWatch Logs group
aws logs create-log-group \
--log-group-name /aws/cloudtrail/logs
# Create IAM role for CloudTrail
aws iam create-role \
--role-name CloudTrail-CloudWatch-Role \
--assume-role-policy-document file://cloudtrail-trust-policy.json
# Attach policy to role
aws iam put-role-policy \
--role-name CloudTrail-CloudWatch-Role \
--policy-name CloudTrail-CloudWatch-Policy \
--policy-document file://cloudtrail-cloudwatch-policy.json
# Update trail to send to CloudWatch
aws cloudtrail update-trail \
--name organization-audit-trail \
--cloud-watch-logs-log-group-arn arn:aws:logs:us-east-1:123456789012:log-group:/aws/cloudtrail/logs \
--cloud-watch-logs-role-arn arn:aws:iam::123456789012:role/CloudTrail-CloudWatch-RoleCreate Security Alerts
Set up CloudWatch alarms for critical events:
# Create metric filter for root account usage
aws logs put-metric-filter \
--log-group-name /aws/cloudtrail/logs \
--filter-name RootAccountUsage \
--filter-pattern '{ $.userIdentity.type = "Root" && $.userIdentity.invokedBy NOT EXISTS && $.eventType != "AwsServiceEvent" }' \
--metric-transformations \
metricName=RootAccountUsageCount,metricNamespace=CloudTrailMetrics,metricValue=1
# Create alarm
aws cloudwatch put-metric-alarm \
--alarm-name RootAccountUsageAlarm \
--alarm-description "Alarm when root account is used" \
--metric-name RootAccountUsageCount \
--namespace CloudTrailMetrics \
--statistic Sum \
--period 300 \
--threshold 1 \
--comparison-operator GreaterThanOrEqualToThreshold \
--evaluation-periods 1 \
--alarm-actions arn:aws:sns:us-east-1:123456789012:security-alertsCommon Security Event Patterns
| Event | CloudWatch Filter Pattern |
|---|---|
| Root account login | { $.userIdentity.type = "Root" } |
| Console login without MFA | { $.eventName = "ConsoleLogin" && $.additionalEventData.MFAUsed != "Yes" } |
| IAM policy changes | { ($.eventName = CreatePolicy) || ($.eventName = DeletePolicy) || ($.eventName = AttachRolePolicy) } |
| Security group changes | { ($.eventName = AuthorizeSecurityGroup*) || ($.eventName = RevokeSecurityGroup*) } |
| Failed authentication | { $.errorCode = "AccessDenied" } |
S3 Lifecycle Policies for Log Retention
Configure cost-effective long-term storage:
# Apply lifecycle policy
aws s3api put-bucket-lifecycle-configuration \
--bucket my-cloudtrail-logs-123456789012 \
--lifecycle-configuration '{
"Rules": [
{
"ID": "CloudTrailArchive",
"Status": "Enabled",
"Prefix": "AWSLogs/",
"Transitions": [
{
"Days": 90,
"StorageClass": "STANDARD_IA"
},
{
"Days": 365,
"StorageClass": "GLACIER"
}
],
"Expiration": {
"Days": 2555
}
}
]
}'This configuration keeps logs in Standard for 90 days, moves to Infrequent Access for a year, then Glacier, with deletion after 7 years.
Query Logs with Athena
Use Amazon Athena for SQL-based log analysis:
-- Create table for CloudTrail logs
CREATE EXTERNAL TABLE cloudtrail_logs (
eventVersion STRING,
userIdentity STRUCT<
type: STRING,
principalId: STRING,
arn: STRING,
accountId: STRING,
userName: STRING>,
eventTime STRING,
eventSource STRING,
eventName STRING,
awsRegion STRING,
sourceIPAddress STRING,
userAgent STRING,
errorCode STRING,
errorMessage STRING
)
ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe'
LOCATION 's3://my-cloudtrail-logs-123456789012/AWSLogs/123456789012/CloudTrail/';
-- Query for failed API calls
SELECT eventTime, eventName, userIdentity.userName, errorCode, sourceIPAddress
FROM cloudtrail_logs
WHERE errorCode IS NOT NULL
AND eventTime > '2026-01-01'
ORDER BY eventTime DESC
LIMIT 100;Verify Trail Configuration
# Get trail status
aws cloudtrail get-trail-status \
--name organization-audit-trail
# Describe trail settings
aws cloudtrail describe-trails \
--trail-name-list organization-audit-trail
# List recent events
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=EventSource,AttributeValue=iam.amazonaws.com \
--max-results 10Best Practices Summary
| Practice | Recommendation |
|---|---|
| Multi-region | Always enable multi-region trails |
| Encryption | Use SSE-KMS with customer-managed keys |
| Validation | Enable log file validation |
| Organization | Use organization trails for all accounts |
| Monitoring | Send to CloudWatch for real-time alerts |
| Retention | Use lifecycle policies for compliance |