AWS CloudTrail records every API call. An attacker operating in AWS leaves a trail of API calls at every step — the challenge is separating attacker activity from the thousands of legitimate API calls that happen every hour.
CloudTrail: The Foundation
Every AWS API call generates a CloudTrail management event with these key fields:
{
"eventTime": "2026-05-18T02:14:23Z",
"eventName": "CreateUser",
"eventSource": "iam.amazonaws.com",
"userIdentity": {
"type": "IAMUser",
"arn": "arn:aws:iam::123456789012:user/dev-alice",
"userName": "dev-alice",
"accountId": "123456789012"
},
"sourceIPAddress": "203.0.113.42",
"userAgent": "aws-cli/2.13.0",
"requestParameters": {
"userName": "backup-svc"
},
"responseElements": {
"user": {
"userName": "backup-svc",
"userId": "AIDAIOSFODNN7EXAMPLE",
"arn": "arn:aws:iam::123456789012:user/backup-svc"
}
}
}
Key fields for detection: eventName, userIdentity.arn, sourceIPAddress, userAgent, requestParameters, errorCode (present on failed calls).
Detection Pattern 1: IAM Credential Creation (Persistence)
Hypothesis: An attacker who has compromised an IAM user creates a new backdoor user or access key to maintain persistent access.
{
"title": "AWS IAM Backdoor User or Access Key Creation",
"logsource": {
"product": "aws",
"service": "cloudtrail"
},
"detection": {
"selection_create_user": {
"eventSource": "iam.amazonaws.com",
"eventName": "CreateUser"
},
"selection_create_key": {
"eventSource": "iam.amazonaws.com",
"eventName": "CreateAccessKey"
},
"filter_known_automation": {
"userIdentity.arn|contains": [
"arn:aws:iam::123456789012:role/terraform-deploy",
"arn:aws:iam::123456789012:role/ci-pipeline"
]
},
"condition": "(1 of selection_*) and not filter_known_automation"
}
}
Tuning note: IAM user creation is rare in mature organizations using SSO/federated identity. If your org uses AWS SSO and no one is supposed to create IAM users manually, any CreateUser event outside known automation is a high-fidelity signal.
Detection Pattern 2: Privilege Escalation via Policy Attachment
Hypothesis: An attacker with limited IAM permissions attaches a high-privilege policy to escalate.
{
"title": "AWS IAM Admin Policy Attached",
"logsource": {
"product": "aws",
"service": "cloudtrail"
},
"detection": {
"selection": {
"eventSource": "iam.amazonaws.com",
"eventName": [
"AttachUserPolicy",
"AttachRolePolicy",
"PutUserPolicy",
"PutRolePolicy"
]
},
"selection_admin_policy": {
"requestParameters.policyArn": [
"arn:aws:iam::aws:policy/AdministratorAccess",
"arn:aws:iam::aws:policy/IAMFullAccess"
]
},
"condition": "selection and selection_admin_policy"
},
"level": "critical"
}
Why critical? Attaching AdministratorAccess is one of the highest-severity actions in an AWS environment — it grants full control over all resources. Legitimate IaC automation should be excluded by source ARN, but any human or unknown automation attaching this policy warrants immediate investigation.
Detection Pattern 3: S3 Exfiltration Signals
Data plane events require explicit enablement. With S3 data events on:
{
"title": "Unusual S3 Bulk Download",
"logsource": {
"product": "aws",
"service": "cloudtrail"
},
"detection": {
"selection": {
"eventSource": "s3.amazonaws.com",
"eventName": "GetObject"
},
"filter_known_services": {
"userIdentity.arn|contains": [
"arn:aws:iam::123456789012:role/backup-service"
]
},
"condition": "selection and not filter_known_services | count() > 100"
},
"falsepositives": [
"Legitimate bulk data processing jobs",
"Analytics or ML training pipeline accessing training data"
],
"level": "medium"
}
Alternative: Alert on GetObject events from external IPs (outside your organization’s IP ranges) against sensitive buckets, regardless of volume threshold.
Detection Pattern 4: Credential Use from Unexpected Location
{
"title": "AWS Credentials Used from Unexpected Source IP",
"logsource": {
"product": "aws",
"service": "cloudtrail"
},
"detection": {
"selection": {
"userIdentity.type": "IAMUser",
"sourceIPAddress|cidr": "203.0.113.0/24"
},
"filter_known_ips": {
"sourceIPAddress|cidr": [
"10.0.0.0/8",
"192.168.0.0/16"
]
},
"condition": "selection and not filter_known_ips"
},
"level": "medium"
}
Practical approach: Build an IP allowlist per IAM user based on their historical source IPs (CloudTrail data). Any call outside the allowlist triggers investigation. This is most effective for service accounts with predictable, stable source IPs.
AWS-Specific Attack Scenarios and Detection
| Attack | CloudTrail event | Detection approach |
|---|---|---|
| EC2 metadata credential theft | GetCallerIdentity from external IP using EC2 role | Role used from non-EC2 source IP |
| S3 bucket discovery | ListBuckets from new/unexpected principal | First-time principal calling ListBuckets |
| Snapshot exfiltration | ModifySnapshotAttribute (set public or share cross-account) | Any public snapshot creation or cross-account share |
| Lambda backdoor | CreateFunction, UpdateFunctionCode, AddPermission | Lambda created/modified outside known deployment pipeline |
| STS role assumption chain | AssumeRole → AssumeRole → AssumeRole | Multi-hop role chain ending in admin role |
| Secrets Manager access | GetSecretValue on high-value secrets | Secrets accessed from non-application principals |
GuardDuty: Managed Detection as Complement
GuardDuty findings most relevant to detection engineers:
| Finding | What it means |
|---|---|
Credential:IAMUser/AnomalousBehavior | Credentials used in anomalous pattern vs baseline |
UnauthorizedAccess:IAMUser/TorIPCaller | API calls from Tor exit node |
Recon:IAMUser/MaliciousIPCaller | Reconnaissance API calls from threat-intel-listed IP |
Persistence:IAMUser/UserPermissions | Privilege escalation via IAM policy changes |
CryptoCurrency:EC2/BitcoinTool | Known crypto mining traffic from EC2 |
Exfiltration:S3/ObjectRead.Unusual | Unusual S3 read pattern (requires S3 Protection) |
GuardDuty findings are good starting points — correlate them with raw CloudTrail to understand the full context before escalating.
CloudGoat (Vulnerable AWS Environment)— Rhino Security Labs Valid Accounts: Cloud Accounts (T1078.004)— MITRE