Skip to content
AWS aws monitoring 5 min read

AWS CloudTrail (Audit Logging)

AWS CloudTrail is the audit log for your AWS account. Every time someone (a person, a script, or another AWS service) makes a call to the AWS API (Application Programming Interface, the way you control AWS), CloudTrail records who did it, what they did, when, and from where. If a security group suddenly opens port 22 to the world, or an S3 bucket gets deleted, CloudTrail is how you find out who pressed the button. It is your “black box flight recorder” for the cloud, and it is essential for security investigations and compliance audits.

What CloudTrail actually records

CloudTrail captures events. Each event is a JSON record describing a single API call. A typical event tells you:

  • Who — the IAM (Identity and Access Management) user, role, or service that made the call (userIdentity).
  • What — the action, like RunInstances or DeleteBucket (eventName).
  • When — a precise timestamp (eventTime).
  • From where — the source IP address and the AWS Region (sourceIPAddress, awsRegion).

CloudTrail sorts events into three types, and the difference matters a lot for both visibility and cost:

Event typeWhat it logsOn by default?Cost
Management eventsControl-plane operations: create/modify/delete resources, change permissions, configure logging. E.g. RunInstances, CreateUser, AttachRolePolicy.Yes (90-day history)Free for the first copy
Data eventsData-plane operations: object-level reads/writes inside resources. E.g. S3 GetObject/PutObject, Lambda Invoke, DynamoDB item changes.NoCharged per event
Insights eventsAutomatically detected unusual API activity (e.g. a sudden spike in DeleteSnapshot).NoCharged per analysis

Gotcha: Data events are the high-volume, high-value records — they show exactly which objects in a bucket were read or which functions were invoked. They are OFF by default and cost extra. This means object-level access to sensitive data is invisible in CloudTrail unless you deliberately turn data events on for that resource.

Event history vs a trail

There are two ways to get at your CloudTrail data, and confusing them is the most common mistake.

Event history (always-on, free, 90 days)

Every account automatically gets Event history: a free, searchable record of management events for the last 90 days. You don’t enable anything — it’s just there. It’s great for “what changed yesterday?” investigations.

The catch: it only keeps 90 days, it only covers management events (no data events), and you cannot query it across long time ranges or archive it. For anything beyond a quick lookback, it is not enough.

A trail (persistent, to S3, forever)

A trail is a configuration you create that continuously delivers events to an S3 (Simple Storage Service) bucket you own. Once delivered, the logs live as long as you keep them — months or years — and you can analyze them with Amazon Athena, ship them to a SIEM (Security Information and Event Management tool), or hand them to auditors.

Tip: For compliance and forensics you almost always need a trail, not event history. The 90-day window disappears silently, and by the time you’re investigating a breach the evidence may be gone. Create a trail on day one.

When to use which:

Event historyTrail to S3
Retention90 daysAs long as you keep the objects
Covers data eventsNoYes (if enabled)
Long-term forensics / complianceNoYes
CostFreeFirst management trail free; S3 storage + data events billed
Setup neededNoneCreate a trail

Creating a trail

The recommended setup is a single organization trail (covering all accounts and all Regions) that logs management events to a dedicated, locked-down S3 bucket.

Console steps

  1. Open the CloudTrail console and choose Trails > Create trail.
  2. Enter a Trail name, e.g. org-audit-trail.
  3. Under Storage location, create a new S3 bucket (e.g. my-org-cloudtrail-logs-0a1b2c3d) or pick an existing one.
  4. (Recommended) Enable Log file SSE-KMS encryption and Log file validation (this lets you prove logs weren’t tampered with).
  5. Choose CloudWatch Logs delivery if you want to alarm on events in near-real-time. Click Next.
  6. Under Event type, keep Management events ticked. To capture object access, tick Data events and add your sensitive S3 buckets and Lambda functions.
  7. Review and choose Create trail.

CLI equivalent

CloudTrail CLI v2. First create and configure the trail:

aws cloudtrail create-trail \
  --name org-audit-trail \
  --s3-bucket-name my-org-cloudtrail-logs-0a1b2c3d \
  --is-multi-region-trail \
  --enable-log-file-validation

aws cloudtrail start-logging --name org-audit-trail

Output:

{
    "Name": "org-audit-trail",
    "S3BucketName": "my-org-cloudtrail-logs-0a1b2c3d",
    "IncludeGlobalServiceEvents": true,
    "IsMultiRegionTrail": true,
    "TrailARN": "arn:aws:cloudtrail:us-east-1:111122223333:trail/org-audit-trail",
    "LogFileValidationEnabled": true
}

Turning on data events for one bucket

Data events are configured separately because they are billed and high-volume. This example logs all object-level reads and writes for one bucket:

aws cloudtrail put-event-selectors \
  --trail-name org-audit-trail \
  --event-selectors '[{
    "ReadWriteType": "All",
    "IncludeManagementEvents": true,
    "DataResources": [{
      "Type": "AWS::S3::Object",
      "Values": ["arn:aws:s3:::my-sensitive-bucket/"]
    }]
  }]'

Cost note: Management events for the first trail are free. Data events cost about $0.10 per 100,000 events delivered. A busy bucket serving millions of GetObject calls per day can run into real money, so scope data events to the buckets and functions that genuinely hold sensitive data — don’t log everything.

Reading and searching events

Quick lookups against the free 90-day history don’t need a trail:

aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=EventName,AttributeValue=RunInstances \
  --max-results 1

Output:

{
    "Events": [{
        "EventId": "8f2a1b3c-...",
        "EventName": "RunInstances",
        "EventTime": "2026-06-14T09:31:22+00:00",
        "Username": "deploy-bot",
        "Resources": [{"ResourceType": "AWS::EC2::Instance", "ResourceName": "i-0a1b2c3d4e5f"}]
    }]
}

For long-term analysis, point Amazon Athena at the trail’s S3 bucket and run SQL over years of logs.

Defining a trail as code

A minimal CloudFormation trail (the S3 bucket and its policy are assumed to exist):

Resources:
  AuditTrail:
    Type: AWS::CloudTrail::Trail
    Properties:
      TrailName: org-audit-trail
      S3BucketName: my-org-cloudtrail-logs-0a1b2c3d
      IsLogging: true
      IsMultiRegionTrail: true
      EnableLogFileValidation: true
      IncludeGlobalServiceEvents: true

Best Practices

  • Create at least one multi-Region trail to S3 on day one — don’t rely on the 90-day event history for anything you might need later.
  • Enable log file validation so you can prove logs weren’t altered after the fact.
  • Lock down the log bucket: block public access, enable encryption, and turn on S3 Object Lock or a strict bucket policy so even an admin can’t quietly delete evidence.
  • Enable data events only for sensitive resources (buckets with PII, key Lambda functions) to balance visibility against cost.
  • Use an organization trail if you run AWS Organizations, so member accounts can’t disable their own auditing.
  • Send a copy to CloudWatch Logs and alarm on dangerous events like StopLogging, DeleteTrail, or root-user logins.
  • Turn on CloudTrail Insights to catch unusual spikes in API activity automatically.
Last updated June 15, 2026
Was this helpful?