Back to Checks
CloudTrail trail S3 bucket is not publicly accessible
cloudtrail_logs_s3_bucket_is_not_publicly_accessible
Service: cloudtrailSeverity: critical
OfficialBuilt-inVerified
Categories:internet-exposed
Resource Type:AwsS3Bucket
CloudTrail log destination S3 buckets are inspected for ACL grants that expose data to the public AllUsers group.
Buckets hosted in other accounts are flagged for out-of-scope review.
Risk
Exposed CloudTrail logs erode confidentiality and integrity.
Adversaries can harvest API activity to map accounts, roles, and keys, enabling reconnaissance and evasion. If write is allowed, logs can be poisoned or deleted, thwarting investigations and compromising incident timelines.
Run this check with Prowler
Run in Prowler CloudRun
prowler aws --checks cloudtrail_logs_s3_bucket_is_not_publicly_accessibleRecommendation
Apply least privilege to the log bucket:
- Enable S3
Block Public Access(account and bucket) - Remove
AllUsers/AuthenticatedUsersACLs; avoid wildcard principals - Permit only CloudTrail and constrain with
aws:SourceArn
Use a dedicated private bucket and monitor for permission changes.
Remediation
CLI
aws s3api put-bucket-acl --bucket <example_resource_name> --acl privateTerraform
# Ensure the CloudTrail S3 bucket ACL is private
resource "aws_s3_bucket_acl" "fix_cloudtrail_logs_bucket" {
bucket = "<example_resource_name>"
acl = "private" # CRITICAL: removes any public (AllUsers) ACL grants
}NativeIaC
# CloudFormation: ensure the CloudTrail S3 bucket ACL is not public
Resources:
CloudTrailLogsBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: <example_resource_name>
AccessControl: Private # CRITICAL: sets bucket ACL to private, removing any AllUsers (public) grantsOther
1Open the AWS S3 Console
2Select the bucket used by CloudTrail
3Go to Permissions > Access control list (ACL)
4Click Edit under Public access, remove any grants to "Everyone (public access)" (uncheck Read/Write)
5Save changes
Check Code
from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.cloudtrail.cloudtrail_client import (
cloudtrail_client,
)
from prowler.providers.aws.services.s3.s3_client import s3_client
class cloudtrail_logs_s3_bucket_is_not_publicly_accessible(Check):
def execute(self):
findings = []
if cloudtrail_client.trails is not None:
for trail in cloudtrail_client.trails.values():
if trail.name:
trail_bucket_is_in_account = False
trail_bucket = trail.s3_bucket
report = Check_Report_AWS(metadata=self.metadata(), resource=trail)
report.region = trail.home_region
report.status = "PASS"
if trail.is_multiregion:
report.status_extended = f"S3 Bucket {trail_bucket} from multiregion trail {trail.name} is not publicly accessible."
else:
report.status_extended = f"S3 Bucket {trail_bucket} from single region trail {trail.name} is not publicly accessible."
for bucket in s3_client.buckets.values():
# Here we need to ensure that acl_grantee is filled since if we don't have permissions to query the api for a concrete region
# (for example due to a SCP) we are going to try access an attribute from a None type
if trail_bucket == bucket.name:
trail_bucket_is_in_account = True
if bucket.acl_grantees:
for grant in bucket.acl_grantees:
if (
grant.URI
== "http://acs.amazonaws.com/groups/global/AllUsers"
):
report.status = "FAIL"
if trail.is_multiregion:
report.status_extended = f"S3 Bucket {trail_bucket} from multiregion trail {trail.name} is publicly accessible."
else:
report.status_extended = f"S3 Bucket {trail_bucket} from single region trail {trail.name} is publicly accessible."
break
# check if trail bucket is a cross account bucket
if not trail_bucket_is_in_account:
report.status = "MANUAL"
report.status_extended = f"Trail {trail.name} bucket ({trail_bucket}) is a cross-account bucket or out of Prowler's audit scope, please check it manually."
findings.append(report)
return findingsReferences
- https://www.trendmicro.com/trendaivisiononecloudriskmanagement/knowledge-base/aws/CloudTrail/cloudtrail-bucket-publicly-accessible.html
- https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-control-block-public-access.html
- https://docs.aws.amazon.com/config/latest/developerguide/cloudtrail-s3-bucket-public-access-prohibited.html
- https://docs.panther.com/alerts/alert-runbooks/built-in-policies/aws-cloudtrail-logs-s3-bucket-not-publicly-accessible