CloudTrail S3 Object-Level Read Events Enabled
Overview
This check verifies that your AWS CloudTrail trails are configured to log S3 object-level read data events. By default, CloudTrail only logs management events (like creating or deleting buckets), not data events (like reading objects). Enabling read data events lets you see who accessed which files in your S3 buckets.
Risk
Without S3 read event logging, you have no visibility into who is accessing your data. This creates serious security and compliance gaps:
- Undetected data exfiltration: Attackers or malicious insiders can download sensitive files without leaving a trace
- Blind spots in incident response: When a breach occurs, you cannot determine what data was accessed
- Compliance failures: Regulations like HIPAA, PCI-DSS, and SOC 2 often require audit trails for data access
- No accountability: You cannot track which users or applications are reading specific files
- Missed anomaly detection: Unusual access patterns (bulk downloads, off-hours access) go unnoticed
Remediation Steps
Prerequisites
You need:
- AWS Console access with permissions to modify CloudTrail trails
- An existing CloudTrail trail (or permission to create one)
Required IAM permissions (for administrators)
Your IAM user or role needs these permissions:
cloudtrail:PutEventSelectorscloudtrail:GetEventSelectorscloudtrail:DescribeTrails
AWS Console Method
-
Open CloudTrail in the AWS Console
- Go to CloudTrail Console in us-east-1
-
Select your trail
- Click Trails in the left sidebar
- Click on the trail name you want to configure
-
Edit Data events
- Scroll down to the Data events section
- Click Edit
-
Add S3 data events
- Under Data event type, select S3
- Click Add data event source if S3 is not already listed
-
Configure read events for all buckets
- For Log selector template, choose Log all events
- Or, for more control:
- Select Custom
- Under Selector name, enter a name like
S3ReadEvents - Set Read to Log (ensure read events are logged)
- For Bucket, choose All current and future S3 buckets to cover everything
-
Save your changes
- Click Save changes
AWS CLI (optional)
Option 1: Enable read events for all S3 buckets
Use the put-event-selectors command to enable read data events across all S3 buckets:
aws cloudtrail put-event-selectors \
--trail-name <trail-name> \
--event-selectors '[
{
"ReadWriteType": "ReadOnly",
"IncludeManagementEvents": true,
"DataResources": [
{
"Type": "AWS::S3::Object",
"Values": ["arn:aws:s3"]
}
]
}
]' \
--region us-east-1
Note: Using "ReadWriteType": "ReadOnly" logs only read events. To log both reads and writes, use "ReadWriteType": "All".
Option 2: Enable read events for specific buckets only
If you only want to log read events for specific buckets (to reduce costs):
aws cloudtrail put-event-selectors \
--trail-name <trail-name> \
--event-selectors '[
{
"ReadWriteType": "ReadOnly",
"IncludeManagementEvents": true,
"DataResources": [
{
"Type": "AWS::S3::Object",
"Values": [
"arn:aws:s3:::my-sensitive-bucket/",
"arn:aws:s3:::another-important-bucket/"
]
}
]
}
]' \
--region us-east-1
Option 3: Using advanced event selectors (recommended for fine-grained control)
Advanced event selectors offer more flexibility. This example logs read events for all S3 buckets:
aws cloudtrail put-event-selectors \
--trail-name <trail-name> \
--advanced-event-selectors '[
{
"Name": "S3ReadEvents",
"FieldSelectors": [
{
"Field": "eventCategory",
"Equals": ["Data"]
},
{
"Field": "resources.type",
"Equals": ["AWS::S3::Object"]
},
{
"Field": "readOnly",
"Equals": ["true"]
}
]
}
]' \
--region us-east-1
CloudFormation (optional)
This template creates a CloudTrail trail with S3 read data events enabled:
AWSTemplateFormatVersion: '2010-09-09'
Description: CloudTrail with S3 object-level read event logging
Parameters:
TrailName:
Type: String
Description: Name of the CloudTrail trail
Default: s3-read-events-trail
S3BucketName:
Type: String
Description: S3 bucket for CloudTrail logs (must already exist with proper policy)
Resources:
CloudTrailWithS3ReadEvents:
Type: AWS::CloudTrail::Trail
Properties:
TrailName: !Ref TrailName
S3BucketName: !Ref S3BucketName
IsLogging: true
IsMultiRegionTrail: true
IncludeGlobalServiceEvents: true
EventSelectors:
- ReadWriteType: ReadOnly
IncludeManagementEvents: true
DataResources:
- Type: AWS::S3::Object
Values:
- arn:aws:s3
Outputs:
TrailArn:
Description: ARN of the CloudTrail trail
Value: !GetAtt CloudTrailWithS3ReadEvents.Arn
Deploy with:
aws cloudformation deploy \
--template-file cloudtrail-s3-read-events.yaml \
--stack-name cloudtrail-s3-read-events \
--parameter-overrides TrailName=s3-read-events-trail S3BucketName=my-cloudtrail-bucket \
--region us-east-1
Note: The S3 bucket must already exist and have a bucket policy that allows CloudTrail to write logs to it.
Terraform (optional)
# Variables
variable "trail_name" {
description = "Name of the CloudTrail trail"
type = string
default = "s3-read-events-trail"
}
variable "s3_bucket_name" {
description = "S3 bucket for CloudTrail logs"
type = string
}
# CloudTrail trail with S3 read data events
resource "aws_cloudtrail" "s3_read_events" {
name = var.trail_name
s3_bucket_name = var.s3_bucket_name
is_multi_region_trail = true
include_global_service_events = true
event_selector {
read_write_type = "ReadOnly"
include_management_events = true
data_resource {
type = "AWS::S3::Object"
values = ["arn:aws:s3"]
}
}
}
# Output
output "trail_arn" {
description = "ARN of the CloudTrail trail"
value = aws_cloudtrail.s3_read_events.arn
}
For advanced event selectors with more control:
resource "aws_cloudtrail" "s3_read_events_advanced" {
name = var.trail_name
s3_bucket_name = var.s3_bucket_name
is_multi_region_trail = true
include_global_service_events = true
advanced_event_selector {
name = "S3ReadEvents"
field_selector {
field = "eventCategory"
equals = ["Data"]
}
field_selector {
field = "resources.type"
equals = ["AWS::S3::Object"]
}
field_selector {
field = "readOnly"
equals = ["true"]
}
}
}
Deploy with:
terraform init
terraform plan -var="trail_name=s3-read-events-trail" -var="s3_bucket_name=my-cloudtrail-bucket"
terraform apply -var="trail_name=s3-read-events-trail" -var="s3_bucket_name=my-cloudtrail-bucket"
Verification
After making changes, verify S3 read event logging is enabled:
-
In the AWS Console:
- Go to CloudTrail > Trails and select your trail
- Scroll to the Data events section
- Verify that S3 is listed with read events enabled
- Check that the scope covers the buckets you need (all buckets or specific ones)
-
Test the logging:
- Download an object from one of your S3 buckets
- Wait 10-15 minutes for the event to be recorded
- Go to CloudTrail > Event history
- Filter by Event name =
GetObject - You should see your download event
CLI verification commands
Check the current event selectors for your trail:
aws cloudtrail get-event-selectors \
--trail-name <trail-name> \
--region us-east-1
Look for this in the output to confirm S3 read events are enabled:
{
"EventSelectors": [
{
"ReadWriteType": "ReadOnly",
"IncludeManagementEvents": true,
"DataResources": [
{
"Type": "AWS::S3::Object",
"Values": ["arn:aws:s3"]
}
]
}
]
}
If ReadWriteType is "All", that also includes read events and passes the check.
If ReadWriteType is "WriteOnly" or there are no DataResources for AWS::S3::Object, read events are not being logged.
Additional Resources
- AWS Documentation: Logging Data Events for S3 Objects
- AWS Documentation: CloudTrail Event Selectors
- AWS Documentation: Advanced Event Selectors
- AWS Best Practices: Security Logging
Notes
-
Cost considerations: S3 data events can generate significant log volume and incur costs. The first copy of management events is free, but data events are charged per 100,000 events. Consider:
- Starting with your most sensitive buckets only
- Using advanced event selectors to exclude high-volume, low-risk operations
- Setting up S3 lifecycle policies on your CloudTrail log bucket
-
High-traffic buckets: For buckets with millions of reads per day, consider selective logging or sampling strategies to control costs.
-
Existing trails: You can add data event logging to an existing trail without creating a new one. The change takes effect immediately for new events.
-
Multi-region trails: If you have a multi-region trail, the data event configuration applies to S3 buckets in all regions.
-
Read vs. Write: This check specifically looks for read events (
GetObject,HeadObject, etc.). You may also want to enable write events (PutObject,DeleteObject) for complete visibility. -
Event delivery delay: S3 data events typically appear in CloudTrail within 15 minutes, but can take longer during high-volume periods.