I’ve been there: you enable CloudTrail for compliance, point it at an S3 bucket, and then two weeks later you realize there are no log files. The bucket sits empty, the audit trail is broken, and you’re scrambling to understand why CloudTrail stopped working. In this post, I’ll walk through exactly what causes this and how to fix it.

The Problem

CloudTrail is enabled and configured, but log files are not appearing in the S3 bucket. You expected to see a folder structure like s3://my-audit-bucket/AWSLogs/ACCOUNT-ID/CloudTrail/... but the bucket is either empty or stopped receiving logs after a certain date. This typically manifests as:

CloudTrail logs missing from S3 bucket for the past X hours
S3 bucket shows no activity in metrics
CloudTrail status shows "Logging enabled" but no delivery

Why Does This Happen?

  • S3 bucket policy deleted or modified — CloudTrail needs explicit permissions: s3:GetBucketAcl, s3:PutObject, and s3:PutObjectAcl on the trail’s bucket path (arn:aws:s3:::bucket/AWSLogs/*). If someone updates the policy to be more restrictive, CloudTrail silently fails.

  • S3 bucket was deleted and recreated — If the bucket was recreated, the bucket policy was not migrated. CloudTrail can no longer write to it even though the configuration still points to the bucket name.

  • CloudTrail trail is paused — The trail might be in a Paused state (logging disabled), which happens when the bucket policy or SNS topic configuration becomes invalid.

  • S3 Block Public Access conflicts — Block Public Access settings can conflict with the bucket policy in subtle ways, especially if the policy includes a Principal: "*" statement.

  • KMS key policy doesn’t allow CloudTrail — If the S3 bucket uses server-side encryption with KMS, the key policy must allow CloudTrail’s AWS account and the cloudtrail.amazonaws.com service principal to decrypt and generate data keys.

The Fix

First, check the trail’s current status:

# Check if trail is logging
aws cloudtrail get-trail-status --name my-trail --region us-east-1

If IsLogging is false, start the trail immediately:

# Start logging
aws cloudtrail start-logging --name my-trail --region us-east-1

Next, verify the S3 bucket name and retrieve the bucket policy:

# Get the bucket name from the trail
aws cloudtrail describe-trails --trail-name-list my-trail --region us-east-1 \
  --query "trailList[0].S3BucketName" --output text

Now check the bucket policy:

# Retrieve and examine the bucket policy
aws s3api get-bucket-policy --bucket my-audit-bucket --output text | jq .

The policy should look like this:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AWSCloudTrailAclCheck",
      "Effect": "Allow",
      "Principal": {
        "Service": "cloudtrail.amazonaws.com"
      },
      "Action": "s3:GetBucketAcl",
      "Resource": "arn:aws:s3:::my-audit-bucket"
    },
    {
      "Sid": "AWSCloudTrailWrite",
      "Effect": "Allow",
      "Principal": {
        "Service": "cloudtrail.amazonaws.com"
      },
      "Action": "s3:PutObject",
      "Resource": "arn:aws:s3:::my-audit-bucket/AWSLogs/*",
      "Condition": {
        "StringEquals": {
          "s3:x-amz-acl": "bucket-owner-full-control"
        }
      }
    }
  ]
}

If the policy is missing or incorrect, create the correct one:

# Create and apply the correct bucket policy
cat > policy.json << 'EOF'
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AWSCloudTrailAclCheck",
      "Effect": "Allow",
      "Principal": {
        "Service": "cloudtrail.amazonaws.com"
      },
      "Action": "s3:GetBucketAcl",
      "Resource": "arn:aws:s3:::my-audit-bucket"
    },
    {
      "Sid": "AWSCloudTrailWrite",
      "Effect": "Allow",
      "Principal": {
        "Service": "cloudtrail.amazonaws.com"
      },
      "Action": "s3:PutObject",
      "Resource": "arn:aws:s3:::my-audit-bucket/AWSLogs/*",
      "Condition": {
        "StringEquals": {
          "s3:x-amz-acl": "bucket-owner-full-control"
        }
      }
    }
  ]
}
EOF

aws s3api put-bucket-policy --bucket my-audit-bucket --policy file://policy.json

Validate the Trail

After fixing the policy, validate the trail to confirm logs are being delivered:

# Validate logs are appearing
aws cloudtrail validate-logs \
  --trail-arn arn:aws:cloudtrail:us-east-1:123456789012:trail/my-trail \
  --start-time 2026-02-01

Is This Safe?

Absolutely. These are standard operations that AWS Administrators perform daily. CloudTrail requires explicit bucket policies to write logs—there’s no way around it. Applying the correct policy doesn’t expose your bucket to unauthorized access.

Key Takeaway

CloudTrail logging failures almost always come down to S3 bucket policy issues. Always verify the policy matches CloudTrail’s requirements, and use get-trail-status to confirm the trail is actively logging. If you’ve just recreated a bucket, remember the policy doesn’t carry over.


Have questions or ran into a different security issue? Connect with me on LinkedIn or X.