How to Enable CloudTrail Audit Logging in AWS

Step-by-step guide to setting up AWS CloudTrail for comprehensive audit logging including multi-region trails, S3 bucket configuration, and log file validation.

10 min readUpdated 2026-01-13

AWS CloudTrail provides comprehensive audit logging of all API activity in your AWS account. Every action taken in the console, CLI, SDK, or by AWS services is recorded, creating an essential security and compliance tool. This guide covers setting up CloudTrail with best practices for production environments.

This article is part of our comprehensive Cloud Security Tips for 2026 guide covering essential practices for protecting your cloud environment.

Why CloudTrail is Essential

CloudTrail enables you to:

  • Security Analysis - Detect unauthorized access and suspicious activity
  • Compliance Auditing - Meet regulatory requirements (SOC 2, HIPAA, PCI DSS)
  • Operational Troubleshooting - Trace issues back to specific API calls
  • Change Tracking - Know who changed what and when

Create a Multi-Region Trail

A multi-region trail captures activity across all AWS regions, ensuring no activity is missed.

Step 1: Navigate to CloudTrail Console

  1. Open the CloudTrail Console
  2. Click Create trail

Step 2: Configure Trail Attributes

  1. Enter a trail name (e.g., "organization-audit-trail")
  2. Enable Enable for all accounts in my organization (if using AWS Organizations)
  3. Select Create new S3 bucket or use an existing bucket
  4. Enable Log file SSE-KMS encryption for enhanced security
  5. Enable Log file validation to detect tampering

Step 3: Choose Log Events

For comprehensive logging:

  • Management events: Read and Write (captures all control plane activity)
  • Data events: Enable for critical S3 buckets and Lambda functions
  • Insights events: Enable to detect unusual API activity patterns

Step 4: Review and Create

  1. Review all settings
  2. Click Create trail

Create Trail Using AWS CLI

For automation and infrastructure-as-code workflows:

# Create S3 bucket for logs
aws s3api create-bucket \
  --bucket my-cloudtrail-logs-123456789012 \
  --region us-east-1

# Apply bucket policy for CloudTrail
aws s3api put-bucket-policy \
  --bucket my-cloudtrail-logs-123456789012 \
  --policy file://cloudtrail-bucket-policy.json

# Create multi-region trail
aws cloudtrail create-trail \
  --name organization-audit-trail \
  --s3-bucket-name my-cloudtrail-logs-123456789012 \
  --is-multi-region-trail \
  --enable-log-file-validation \
  --include-global-service-events

# Start logging
aws cloudtrail start-logging \
  --name organization-audit-trail

S3 Bucket Policy for CloudTrail

Create cloudtrail-bucket-policy.json:

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

Configure Log File Validation

Log file validation ensures logs haven't been tampered with:

# Enable log file validation on existing trail
aws cloudtrail update-trail \
  --name organization-audit-trail \
  --enable-log-file-validation

# Validate log file integrity
aws cloudtrail validate-logs \
  --trail-arn arn:aws:cloudtrail:us-east-1:123456789012:trail/organization-audit-trail \
  --start-time 2026-01-01T00:00:00Z \
  --end-time 2026-01-13T23:59:59Z

CloudTrail creates digest files every hour that contain hashes of log files, enabling detection of any modifications.


Enable CloudTrail Insights

CloudTrail Insights automatically detects unusual API activity:

# Enable Insights on a trail
aws cloudtrail put-insight-selectors \
  --trail-name organization-audit-trail \
  --insight-selectors '[{"InsightType": "ApiCallRateInsight"}, {"InsightType": "ApiErrorRateInsight"}]'

Insights can detect:

  • Unusual spikes in API call volume
  • Elevated error rates indicating potential attacks
  • Anomalous write management events

Send Logs to CloudWatch

Integrate with CloudWatch Logs for real-time monitoring:

# Create CloudWatch Logs group
aws logs create-log-group \
  --log-group-name /aws/cloudtrail/logs

# Create IAM role for CloudTrail
aws iam create-role \
  --role-name CloudTrail-CloudWatch-Role \
  --assume-role-policy-document file://cloudtrail-trust-policy.json

# Attach policy to role
aws iam put-role-policy \
  --role-name CloudTrail-CloudWatch-Role \
  --policy-name CloudTrail-CloudWatch-Policy \
  --policy-document file://cloudtrail-cloudwatch-policy.json

# Update trail to send to CloudWatch
aws cloudtrail update-trail \
  --name organization-audit-trail \
  --cloud-watch-logs-log-group-arn arn:aws:logs:us-east-1:123456789012:log-group:/aws/cloudtrail/logs \
  --cloud-watch-logs-role-arn arn:aws:iam::123456789012:role/CloudTrail-CloudWatch-Role

Create Security Alerts

Set up CloudWatch alarms for critical events:

# Create metric filter for root account usage
aws logs put-metric-filter \
  --log-group-name /aws/cloudtrail/logs \
  --filter-name RootAccountUsage \
  --filter-pattern '{ $.userIdentity.type = "Root" && $.userIdentity.invokedBy NOT EXISTS && $.eventType != "AwsServiceEvent" }' \
  --metric-transformations \
    metricName=RootAccountUsageCount,metricNamespace=CloudTrailMetrics,metricValue=1

# Create alarm
aws cloudwatch put-metric-alarm \
  --alarm-name RootAccountUsageAlarm \
  --alarm-description "Alarm when root account is used" \
  --metric-name RootAccountUsageCount \
  --namespace CloudTrailMetrics \
  --statistic Sum \
  --period 300 \
  --threshold 1 \
  --comparison-operator GreaterThanOrEqualToThreshold \
  --evaluation-periods 1 \
  --alarm-actions arn:aws:sns:us-east-1:123456789012:security-alerts

Common Security Event Patterns

EventCloudWatch Filter Pattern
Root account login{ $.userIdentity.type = "Root" }
Console login without MFA{ $.eventName = "ConsoleLogin" && $.additionalEventData.MFAUsed != "Yes" }
IAM policy changes{ ($.eventName = CreatePolicy) || ($.eventName = DeletePolicy) || ($.eventName = AttachRolePolicy) }
Security group changes{ ($.eventName = AuthorizeSecurityGroup*) || ($.eventName = RevokeSecurityGroup*) }
Failed authentication{ $.errorCode = "AccessDenied" }

S3 Lifecycle Policies for Log Retention

Configure cost-effective long-term storage:

# Apply lifecycle policy
aws s3api put-bucket-lifecycle-configuration \
  --bucket my-cloudtrail-logs-123456789012 \
  --lifecycle-configuration '{
    "Rules": [
      {
        "ID": "CloudTrailArchive",
        "Status": "Enabled",
        "Prefix": "AWSLogs/",
        "Transitions": [
          {
            "Days": 90,
            "StorageClass": "STANDARD_IA"
          },
          {
            "Days": 365,
            "StorageClass": "GLACIER"
          }
        ],
        "Expiration": {
          "Days": 2555
        }
      }
    ]
  }'

This configuration keeps logs in Standard for 90 days, moves to Infrequent Access for a year, then Glacier, with deletion after 7 years.


Query Logs with Athena

Use Amazon Athena for SQL-based log analysis:

-- Create table for CloudTrail logs
CREATE EXTERNAL TABLE cloudtrail_logs (
  eventVersion STRING,
  userIdentity STRUCT<
    type: STRING,
    principalId: STRING,
    arn: STRING,
    accountId: STRING,
    userName: STRING>,
  eventTime STRING,
  eventSource STRING,
  eventName STRING,
  awsRegion STRING,
  sourceIPAddress STRING,
  userAgent STRING,
  errorCode STRING,
  errorMessage STRING
)
ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe'
LOCATION 's3://my-cloudtrail-logs-123456789012/AWSLogs/123456789012/CloudTrail/';

-- Query for failed API calls
SELECT eventTime, eventName, userIdentity.userName, errorCode, sourceIPAddress
FROM cloudtrail_logs
WHERE errorCode IS NOT NULL
  AND eventTime > '2026-01-01'
ORDER BY eventTime DESC
LIMIT 100;

Verify Trail Configuration

# Get trail status
aws cloudtrail get-trail-status \
  --name organization-audit-trail

# Describe trail settings
aws cloudtrail describe-trails \
  --trail-name-list organization-audit-trail

# List recent events
aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=EventSource,AttributeValue=iam.amazonaws.com \
  --max-results 10

Best Practices Summary

PracticeRecommendation
Multi-regionAlways enable multi-region trails
EncryptionUse SSE-KMS with customer-managed keys
ValidationEnable log file validation
OrganizationUse organization trails for all accounts
MonitoringSend to CloudWatch for real-time alerts
RetentionUse lifecycle policies for compliance

Frequently Asked Questions

Find answers to common questions

Management events (also called control plane events) capture API operations that manage AWS resources, such as creating EC2 instances, modifying IAM policies, or configuring VPCs. These are logged by default. Data events capture resource operations performed on or within a resource, such as S3 object-level activity (GetObject, PutObject) or Lambda function invocations. Data events must be explicitly enabled and incur additional costs due to high volume.

Need Professional Help?

Our team of experts can help you implement and configure these solutions for your organization.