CloudTrail trail logs management events for read and write operations
CloudTrail trails record management events (read and write) in every AWS region and are actively logging, using a multi-region trail or per-region coverage.
Risk
Without region-wide management event logging, changes to identities, networking, and audit settings can go untracked.
Adversaries can operate in overlooked regions to create resources, modify permissions, or disable logging, undermining integrity, confidentiality, and incident response.
Run this check with Prowler
Run in Prowler Cloudprowler aws --checks cloudtrail_multi_region_enabled_logging_management_eventsRecommendation
Enable a multi-region CloudTrail that logs management events for read and write in all regions.
Centralize logs in a separate, locked-down account; apply least privilege, encryption, retention, and integrity validation; and protect trails and storage with tamper-evident, deny-delete controls for defense-in-depth.
Remediation
Terraform
# Terraform: enable multi-region and log management events (read & write)
resource "aws_cloudtrail" "<example_resource_name>" {
name = "<example_resource_name>"
s3_bucket_name = "<example_resource_name>"
is_multi_region_trail = true # CRITICAL: apply the trail to all regions
event_selector {
include_management_events = true # CRITICAL: log management events
read_write_type = "All" # CRITICAL: log both read & write
}
}NativeIaC
# CloudFormation: enable multi-region and log management events (read & write)
Resources:
<example_resource_name>:
Type: AWS::CloudTrail::Trail
Properties:
S3BucketName: <example_resource_name>
IsMultiRegionTrail: true # CRITICAL: apply the trail to all regions
EventSelectors:
- IncludeManagementEvents: true # CRITICAL: log management events
ReadWriteType: All # CRITICAL: log both read and writeOther
Check Code
from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.cloudtrail.cloudtrail_client import (
cloudtrail_client,
)
class cloudtrail_multi_region_enabled_logging_management_events(Check):
def execute(self):
findings = []
if cloudtrail_client.trails is not None:
for region in cloudtrail_client.regional_clients.keys():
report = Check_Report_AWS(
metadata=self.metadata(), resource=cloudtrail_client.trails
)
report.status = "FAIL"
report.status_extended = "No CloudTrail trails enabled and logging management events were found."
report.region = region
report.resource_id = cloudtrail_client.audited_account
report.resource_arn = cloudtrail_client._get_trail_arn_template(region)
trail_is_logging_management_events = False
for trail in cloudtrail_client.trails.values():
if trail.region == region or trail.is_multiregion:
if trail.is_logging:
for event in trail.data_events:
# Classic event selectors
if not event.is_advanced:
# Check if trail has IncludeManagementEvents and ReadWriteType is All
if (
event.event_selector["ReadWriteType"] == "All"
and event.event_selector[
"IncludeManagementEvents"
]
):
trail_is_logging_management_events = True
# Advanced event selectors
elif event.is_advanced:
if event.event_selector.get(
"Name"
) == "Management events selector" and all(
[
field["Field"] != "readOnly"
for field in event.event_selector[
"FieldSelectors"
]
]
):
trail_is_logging_management_events = True
if trail_is_logging_management_events:
report = Check_Report_AWS(
metadata=self.metadata(), resource=trail
)
report.region = region
report.status = "PASS"
if trail.is_multiregion:
report.status_extended = f"Trail {trail.name} from home region {trail.home_region} is multi-region, is logging and have management events enabled."
else:
report.status_extended = f"Trail {trail.name} in region {trail.home_region} is logging and have management events enabled."
# Since there exists a logging trail in that region there is no point in checking the remaining trails
# Store the finding and exit the loop
findings.append(report)
break
if report.status == "FAIL":
findings.append(report)
return findings