| name | cloudtrail |
| description | Manage AWS CloudTrail trails, event history, insights, and log analysis via AWS CLI. |
| metadata | {"openclaw":{"emoji":"📜","requires":{"bins":["aws"]}}} |
AWS CloudTrail
Use this skill for audit and compliance: viewing API event history, managing trails, querying CloudTrail Lake, analyzing security events, and configuring insights for anomaly detection.
Prerequisites
- AWS CLI v2 configured with valid credentials
- IAM permissions:
cloudtrail:* for full access, or scoped policies
- S3 bucket for trail log delivery
Common Operations
Event History (Read-Only)
aws cloudtrail lookup-events \
--max-results 20 \
--query 'Events[*].[EventTime,EventName,Username,EventSource]' --output table
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=Username,AttributeValue=<username> \
--max-results 20 \
--query 'Events[*].[EventTime,EventName,EventSource]' --output table
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=EventName,AttributeValue=RunInstances \
--max-results 10
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=ResourceName,AttributeValue=<resource-id> \
--max-results 10
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=EventSource,AttributeValue=s3.amazonaws.com \
--start-time $(date -u -v-1d +%Y-%m-%dT%H:%M:%SZ) \
--end-time $(date -u +%Y-%m-%dT%H:%M:%SZ)
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=AccessKeyId,AttributeValue=<access-key-id>
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=ReadOnly,AttributeValue=false \
--max-results 20 \
--query 'Events[*].[EventTime,EventName,Username]' --output table
Trails (Read-Only)
aws cloudtrail describe-trails \
--query 'trailList[*].[Name,S3BucketName,IsMultiRegionTrail,IsOrganizationTrail,HasInsightSelectors]' \
--output table
aws cloudtrail get-trail-status --name <trail-name>
aws cloudtrail get-trail --name <trail-name>
aws cloudtrail get-event-selectors --trail-name <trail-name>
aws cloudtrail get-insight-selectors --trail-name <trail-name>
aws cloudtrail list-event-data-stores \
--query 'EventDataStores[*].[Name,EventDataStoreArn,Status]' --output table
aws cloudtrail list-channels --output table
Create and Configure
⚠️ Cost note: First trail delivering management events is free. Additional trails: $2.00 per 100,000 management events. Data events: $0.10 per 100,000 events. CloudTrail Lake: $2.50/GB ingested, $0.005/GB scanned.
aws cloudtrail create-trail \
--name <trail-name> \
--s3-bucket-name <bucket-name> \
--is-multi-region-trail \
--enable-log-file-validation
aws cloudtrail start-logging --name <trail-name>
aws cloudtrail put-event-selectors \
--trail-name <trail-name> \
--event-selectors '[{
"ReadWriteType": "All",
"IncludeManagementEvents": true,
"DataResources": [{"Type": "AWS::S3::Object", "Values": ["arn:aws:s3"]}]
}]'
aws cloudtrail put-event-selectors \
--trail-name <trail-name> \
--event-selectors '[{
"ReadWriteType": "All",
"IncludeManagementEvents": true,
"DataResources": [{"Type": "AWS::Lambda::Function", "Values": ["arn:aws:lambda:<region>:<account>:function:<function-name>"]}]
}]'
aws cloudtrail put-event-selectors \
--trail-name <trail-name> \
--advanced-event-selectors '[{
"Name": "S3PutOnly",
"FieldSelectors": [
{"Field": "eventCategory", "Equals": ["Data"]},
{"Field": "resources.type", "Equals": ["AWS::S3::Object"]},
{"Field": "readOnly", "Equals": ["false"]}
]
}]'
aws cloudtrail put-insight-selectors \
--trail-name <trail-name> \
--insight-selectors '[
{"InsightType": "ApiCallRateInsight"},
{"InsightType": "ApiErrorRateInsight"}
]'
aws cloudtrail update-trail \
--name <trail-name> \
--cloud-watch-logs-log-group-arn <log-group-arn> \
--cloud-watch-logs-role-arn <role-arn>
aws cloudtrail create-event-data-store \
--name <store-name> \
--retention-period 90 \
--advanced-event-selectors '[{
"Name": "AllManagement",
"FieldSelectors": [{"Field": "eventCategory", "Equals": ["Management"]}]
}]'
CloudTrail Lake Queries
QUERY_ID=$(aws cloudtrail start-query \
--query-statement "SELECT eventTime, eventName, userIdentity.arn, sourceIPAddress FROM <event-data-store-id> WHERE eventTime > '2024-01-01 00:00:00' AND eventName = 'ConsoleLogin' ORDER BY eventTime DESC LIMIT 50" \
--query 'QueryId' --output text)
aws cloudtrail describe-query --query-id $QUERY_ID
aws cloudtrail get-query-results --query-id $QUERY_ID
Delete / Destructive
🛑 DESTRUCTIVE — Always confirm with the user before executing any of these commands.
aws cloudtrail stop-logging --name <trail-name>
aws cloudtrail delete-trail --name <trail-name>
aws cloudtrail delete-event-data-store --event-data-store <store-arn>
Safety Rules
- NEVER stop logging or delete trails without explicit user confirmation — creates audit gaps.
- NEVER expose or log AWS credentials or sensitive event details.
- ALWAYS confirm the trail name and region before modifications.
- ALWAYS recommend log file validation to detect tampering.
- WARN about cost implications of data events (high volume).
- WARN that stopping logging creates compliance risk.
Best Practices
- Enable at least one multi-region trail with log file validation.
- Enable CloudTrail Insights for anomaly detection on API calls.
- Send logs to CloudWatch for real-time monitoring and alerting.
- Enable S3 data events for security-sensitive buckets.
- Use CloudTrail Lake for complex ad-hoc security investigations.
Common Patterns
Pattern: Investigate Who Changed a Resource
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=ResourceName,AttributeValue=<sg-id> \
--query 'Events[*].[EventTime,EventName,Username,sourceIPAddress]' \
--output table
Pattern: Find Console Logins
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=EventName,AttributeValue=ConsoleLogin \
--max-results 20 \
--query 'Events[*].[EventTime,Username,CloudTrailEvent]' --output text | while read line; do
echo "$line" | jq -r '.sourceIPAddress // "N/A"' 2>/dev/null
done
Pattern: Detect Unauthorized API Calls
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=EventName,AttributeValue=ConsoleLogin \
--start-time $(date -u -v-7d +%Y-%m-%dT%H:%M:%SZ) \
--max-results 50 | jq '.Events[] | select(.CloudTrailEvent | fromjson | .errorCode == "AccessDenied")'
Troubleshooting
| Error | Cause | Fix |
|---|
TrailNotFoundException | Trail doesn't exist | Verify with describe-trails |
InsufficientS3BucketPolicyException | S3 bucket missing CloudTrail policy | Add CloudTrail service permissions to bucket policy |
InsufficientSnsTopicPolicyException | SNS topic missing permissions | Add cloudtrail.amazonaws.com publish permission |
| No events in lookup | Events beyond 90-day window | Use CloudTrail Lake or query S3 logs directly |
| Delayed event delivery | Normal — can take up to 15 min | CloudTrail is not real-time; wait and retry |
| Log file validation failed | Possible log tampering | Investigate immediately — this is a security incident |