AWS CloudTrail Log Format: Field Reference and Example Records
Published
One record per API call made in an AWS account: who called it (identity and credentials), which service and operation, from which address and client, with what parameters, and whether it succeeded or was denied.
Official documentation: CloudTrail record contents (AWS CloudTrail User Guide)
Sample record
{
"eventVersion": "1.08",
"userIdentity": {
"type": "IAMUser",
"arn": "arn:aws:iam::123456789012:user/alice",
"userName": "alice",
"accountId": "123456789012"
},
"eventTime": "2024-01-15T09:05:12Z",
"eventSource": "s3.amazonaws.com",
"eventName": "ListBuckets",
"awsRegion": "us-east-1",
"sourceIPAddress": "203.0.113.10",
"userAgent": "aws-cli/2.13.0 Python/3.11.4 Darwin/22.6.0", From the LogTriage parser test corpus — synthetic data, no real hosts or users.
Field reference
| Field | Type | Meaning | Why it matters for security |
|---|---|---|---|
| eventVersione.g. 1.08 | string | Version of the CloudTrail event record schema. | Tells a parser which fields and sub-objects to expect; new versions add fields rather than renaming them. |
| userIdentity.typee.g. IAMUser | string | Kind of identity that made the call: IAMUser, AssumedRole, AWSService, Root and others. | AssumedRole records carry session detail; Root activity on a day-to-day basis is almost always worth a question. |
| userIdentity.arne.g. arn:aws:iam::123456789012:user/dev-contractor | string | Full ARN of the calling principal. | The most reliable actor key for grouping activity — usernames repeat across accounts, ARNs do not. |
| userIdentity.userNamee.g. alice | string | Friendly name of the IAM user or role session, when the identity type has one. | Convenient for timelines, but absent for some identity types, so never key a detection on it alone. |
| userIdentity.accessKeyIde.g. AKIAIOSFODNN7EXAMPLE | string | Access key used to sign the request; temporary session keys start with ASIA. | Pivot on the key to see every call a leaked credential made, and to tell long-lived keys from session credentials. |
| eventTimee.g. 2024-01-15T03:12:44Z | datetime (UTC) | When the request completed, as recorded by the service, in UTC. | Build the attack timeline on this field; delivery time to S3 is later and varies. |
| eventSourcee.g. iam.amazonaws.com | string | Service endpoint the call went to. | Scopes a hunt to one control plane: iam.amazonaws.com, sts.amazonaws.com and cloudtrail.amazonaws.com carry most escalation and tampering activity. |
| eventNamee.g. AttachUserPolicy | string | The API operation that was called. | The core detection field — CreatePolicy, AttachUserPolicy, AssumeRole, StopLogging and similar names describe the action in one token. |
| awsRegione.g. us-east-1 | string | Region the request was handled in. | Activity in regions your organization does not use is a classic sign of a stolen key being exercised. |
| sourceIPAddresse.g. 203.0.113.10 | string | Address the request came from; for calls an AWS service makes on your behalf it holds the service's DNS name instead of an IP. | Group by this to separate office and VPN egress from an attacker's host, but expect non-IP values in some records. |
| userAgente.g. python-requests/2.28.0 | string | Client that made the call — CLI, SDK, console or a raw HTTP library. | A human's account suddenly calling IAM through python-requests instead of aws-cli or Boto3 is a strong signal. |
| errorCodee.g. AccessDenied | string | Present only when the call failed; names the service error returned. | Denied calls are still recorded, so bursts of AccessDenied map out exactly what an attacker tried to reach. |
| errorMessagee.g. User: arn:aws:iam::123456789012:user/dev-contractor is not authorized to perform: iam:DeleteAccountPasswordPolicy | string | Text of the service error, usually naming the principal and the action that was refused. | Reads as a confession of intent — it states the exact permission the caller was reaching for. |
| requestParameterse.g. {"bucketName": "prod-customer-data-backup"} | object or null | Parameters the caller sent, shaped per API; null when the operation takes none or none were logged. | Where the damage is visible — the policy document, the bucket name, the role ARN being assumed. |
| responseElementse.g. null | object or null | What the service returned for mutating calls; typically null for read-only operations. | Confirms an action took effect, for example the ARN of a policy that was actually created. |
| eventIDe.g. a1b2c3d4-e5f6-7890-abcd-ef1234567890 | string (GUID) | Unique identifier for the event record. | Use it to deduplicate records that arrive twice and to cite a single call in an incident report. |
What it records
A CloudTrail record describes one API call in an AWS account: the time, the service (eventSource) and operation (eventName), the calling identity and the credentials it used (userIdentity), the source address and client (sourceIPAddress, userAgent), the parameters sent and values returned (requestParameters, responseElements), and, when the call failed, errorCode and errorMessage.
Management events — control-plane operations such as creating a policy, attaching it to a user or assuming a role — are the default content. Data events, such as individual S3 object reads or Lambda invocations, are recorded only when a trail is configured to capture them.
In log files written to S3 the records are gzipped JSON with a top-level Records array, exactly as in the samples on this page.
Where to get it
- Event history in the CloudTrail console: the last 90 days of management events for the current region, searchable and downloadable, with no setup required.
- A trail delivering log files to an S3 bucket, optionally multi-region and optionally organization-wide. This is what gives you retention beyond 90 days and the only place data events appear.
- CloudWatch Logs, if the trail is configured to send events there as well, for near-term queries and metric filters.
- CloudTrail Lake, which stores events as a queryable event data store.
Trails can also write digest files so the delivered log files can be checked for tampering with log file integrity validation.
Parsing pitfalls
requestParametersandresponseElementsare shaped per API. There is no fixed schema; the same key can be a string in one operation and an object in another. Flatten them lazily, or store them as raw JSON and extract pereventName.- Nulls everywhere. Both fields are frequently
null, as isuserIdentity.accessKeyIdon some records. A parser that assumes objects will drop events. sourceIPAddressis not always an IP. When an AWS service calls on your behalf, the field carries the service’s DNS name, which breaks IP-typed columns and geolocation.- Delivery lag and ordering.
eventTimeis set by the service, files arrive in batches, and records within a file are not in time order. Sort before building a timeline, and do not read a gap at the end of the data as silence. - Duplicates happen. Deduplicate on
eventIDrather than assuming one delivery per call. - Read-only calls look harmless.
ListBuckets,DescribeInstancesandGetBucketPolicyare routine for administrators and also exactly what reconnaissance looks like; context, not the operation name, separates them.
Detection ideas
- Privilege escalation:
CreatePolicywith a wildcard action followed byAttachUserPolicyon the caller’s own user, thenAssumeRole— the sequence in the malicious sample and the basis of the CloudTrail IAM privilege-escalation rule. - Logging tampering:
StopLogging,DeleteTrail,PutEventSelectorsor deletion of the log bucket, especially from an identity that has never touched CloudTrail before. - Permission probing: many
AccessDeniedresults for oneuserIdentity.arnacross differenteventSourcevalues in a short window. - Stolen key use: an
accessKeyIdappearing from a newsourceIPAddress, a newawsRegionor a scripteduserAgentsuch as python-requests when the owner normally uses the CLI. - Data staging:
GetBucketPolicyandListObjectsagainst production data buckets by an identity whose job is development.
The free browser analyzer runs these checks on a CloudTrail JSON export without uploading it.
Detections and guides for AWS CloudTrail
Frequently Asked Questions
- Why is there no GetObject or PutObject activity in my trail?
- Object-level S3 calls are data events, and a trail records only management events unless data events are explicitly enabled and selected for the buckets you care about. Data events are billed separately and can be very high volume, so check the trail's event selectors before concluding that nobody read an object.
- Does CloudTrail log calls that were denied?
- Yes. A refused call is still an API call, and the record carries errorCode and errorMessage alongside the normal identity, source address and parameter fields. Those failures are some of the best material in the log, because the error message names the exact permission the principal was reaching for.
- How far back does Event history go?
- Event history in the console keeps the last 90 days of management events per region at no extra charge. For anything older, or for data events and cross-account search, you need a trail delivering to S3 or events stored in CloudTrail Lake, configured before the incident happened.
- Why do IAM events all show us-east-1?
- IAM, STS and other global services record their events in a single region, so an organization that never deploys to us-east-1 will still see IAM activity there. Do not treat that region alone as anomalous; judge the identity, source address and user agent instead.
Analyze a AWS CloudTrail file in your browser
The free analyzer detects this format, parses every field above and flags attack patterns — the file never leaves your machine. For threat-intel enrichment and an AI-written incident report, run it through LogTriage.