CLOUDTRAIL & AZURE MONITOR LOG ANALYSIS FOR SOC
A practical reference for detecting threats, investigating incidents, and building detections in AWS CloudTrail and Azure Monitor/Sentinel.
CLOUDTRAIL FUNDAMENTALS#
# Enable CloudTrail (all regions, management + data events) aws cloudtrail create-trail \ --name security-trail \ --s3-bucket-name cloudtrail-logs-bucket \ --is-multi-region-trail \ --enable-log-file-validation aws cloudtrail start-logging --name security-trail # Query CloudTrail with AWS CLI aws cloudtrail lookup-events --lookup-attributes AttributeKey=EventName,AttributeValue=ConsoleLogin # Query with time range aws cloudtrail lookup-events \ --start-time "2026-03-01T00:00:00Z" \ --end-time "2026-03-19T23:59:59Z" \ --lookup-attributes AttributeKey=EventName,AttributeValue=CreateUser # Query by username aws cloudtrail lookup-events \ --lookup-attributes AttributeKey=Username,AttributeValue=suspicious-user # CloudTrail log structure (key fields): # eventTime, eventName, eventSource, awsRegion # sourceIPAddress, userAgent # userIdentity.type, userIdentity.arn, userIdentity.accountId # requestParameters, responseElements # errorCode, errorMessage
CRITICAL CLOUDTRAIL EVENTS TO MONITOR#
# AUTHENTICATION & ACCESS ConsoleLogin # Console sign-in (check MFA, sourceIP) ConsoleLoginFailure # Failed console login SwitchRole # User assumed another role GetSessionToken # Temporary credentials requested GetFederationToken # Federated access token created AssumeRole # Role assumption AssumeRoleWithSAML # SAML-based federation AssumeRoleWithWebIdentity # Web identity federation # USER & CREDENTIAL MANAGEMENT CreateUser # New IAM user created CreateLoginProfile # Console password set for user CreateAccessKey # New access key pair created UpdateLoginProfile # Password changed DeleteUser # User deletion (covering tracks) AddUserToGroup # Group membership change AttachUserPolicy # Direct policy attachment # POLICY & PERMISSION CHANGES CreatePolicy # New IAM policy created CreatePolicyVersion # Policy updated (check for wildcards) AttachRolePolicy # Policy attached to role PutRolePolicy # Inline policy added to role PutUserPolicy # Inline policy added to user AttachGroupPolicy # Policy attached to group # PERSISTENCE MECHANISMS CreateRole # New role created UpdateAssumeRolePolicy # Trust policy modified CreateServiceLinkedRole # Service-linked role created CreateInstanceProfile # EC2 instance profile created AddRoleToInstanceProfile # Role added to instance profile # DEFENSE EVASION StopLogging # CloudTrail logging stopped *** HIGH PRIORITY *** DeleteTrail # CloudTrail trail deleted *** HIGH PRIORITY *** UpdateTrail # Trail configuration changed PutEventSelectors # Event filtering changed DisableRule # CloudWatch/EventBridge rule disabled DeleteFlowLogs # VPC flow logs deleted DeleteDetector # GuardDuty disabled # DATA EXFILTRATION INDICATORS GetObject # S3 object downloaded (data events) PutBucketPolicy # Bucket policy changed (may allow public) PutBucketAcl # Bucket ACL changed CreateSnapshot # EBS snapshot (data theft) ModifySnapshotAttribute # Snapshot shared externally ModifyImageAttribute # AMI shared externally CopySnapshot # Cross-region/account snapshot copy AuthorizeSecurityGroupIngress # Firewall opened # RESOURCE CREATION (CRYPTOMINING / ABUSE) RunInstances # EC2 instances launched CreateFunction # Lambda function created CreateStack # CloudFormation stack deployed
ATHENA QUERIES FOR CLOUDTRAIL#
# Create Athena table for CloudTrail
CREATE EXTERNAL TABLE cloudtrail_logs (
eventversion STRING, useridentity STRUCT<type:STRING,principalid:STRING,arn:STRING,accountid:STRING>,
eventtime STRING, eventsource STRING, eventname STRING, awsregion STRING,
sourceipaddress STRING, useragent STRING, requestparameters STRING,
responseelements STRING, errorcode STRING, errormessage STRING
) ROW FORMAT SERDE 'org.apache.hive.hcatalog.data.JsonSerDe'
LOCATION 's3://cloudtrail-bucket/AWSLogs/<account-id>/CloudTrail/';
# Failed console logins
SELECT eventtime, useridentity.arn, sourceipaddress, errormessage
FROM cloudtrail_logs
WHERE eventname = 'ConsoleLogin' AND errorcode = 'Failed'
ORDER BY eventtime DESC LIMIT 100;
# Access key creation
SELECT eventtime, useridentity.arn, requestparameters, sourceipaddress
FROM cloudtrail_logs
WHERE eventname = 'CreateAccessKey'
ORDER BY eventtime DESC;
# CloudTrail tampering
SELECT eventtime, useridentity.arn, eventname, sourceipaddress
FROM cloudtrail_logs
WHERE eventname IN ('StopLogging', 'DeleteTrail', 'UpdateTrail', 'PutEventSelectors')
ORDER BY eventtime DESC;
# Unusual AssumeRole activity
SELECT eventtime, useridentity.arn, requestparameters, sourceipaddress
FROM cloudtrail_logs
WHERE eventname = 'AssumeRole'
AND sourceipaddress NOT LIKE '10.%'
ORDER BY eventtime DESC LIMIT 200;
# S3 data exfiltration (large number of GetObject calls)
SELECT useridentity.arn, COUNT(*) as get_count, MIN(eventtime) as first_seen, MAX(eventtime) as last_seen
FROM cloudtrail_logs
WHERE eventname = 'GetObject'
GROUP BY useridentity.arn
HAVING COUNT(*) > 100
ORDER BY get_count DESC;
AZURE ACTIVITY LOG KEY EVENTS#
# HIGH PRIORITY EVENTS # Authentication "Sign-in activity" # Azure AD sign-in logs "Risky sign-in" # Identity Protection alerts "MFA denied" # Blocked MFA attempt "User registered security info" # MFA registration "Consent to application" # OAuth consent grant # Role & Permission Changes "Add member to role" # Role assignment "Add eligible member to role in PIM" # PIM role activation "Remove member from role" # Role removal "Add role assignment" # Azure RBAC change # User & Group Management "Add user" # New user created "Delete user" # User deleted "Update user" # User properties changed "Add member to group" # Group membership "Add owner to group" # Group ownership "Reset user password" # Password reset "Invite external user" # Guest user invited # Application & Service Principal "Add application" # App registration "Add service principal" # Service principal created "Add service principal credentials" # Secret/cert added "Consent to application" # App consent granted "Add app role assignment to service principal" # API permissions granted "Add owner to application" # App ownership changed # Subscription & Resource "Create or Update Virtual Machine" # VM creation "Create role assignment" # RBAC assignment "Delete resource group" # Resource deletion "Create or Update Network Security Group" # NSG changes "Delete Network Security Group Rule" # Firewall rule removed # Defense Evasion "Delete diagnostic setting" # Logging disabled "Update diagnostic setting" # Logging modified "Deletes the activity log profile" # Activity log export removed
KQL QUERIES FOR MICROSOFT SENTINEL#
# Failed sign-ins with high volume (brute force) SigninLogs | where ResultType != "0" | summarize FailedCount=count(), DistinctUsers=dcount(UserPrincipalName) by IPAddress, bin(TimeGenerated, 1h) | where FailedCount > 20 | sort by FailedCount desc # Successful login after multiple failures (credential stuffing success) let FailedLogins = SigninLogs | where ResultType != "0" | summarize FailCount=count() by UserPrincipalName, IPAddress | where FailCount > 5; SigninLogs | where ResultType == "0" | join kind=inner FailedLogins on UserPrincipalName, IPAddress | project TimeGenerated, UserPrincipalName, IPAddress, AppDisplayName, FailCount # Impossible travel detection SigninLogs | where ResultType == "0" | summarize Locations=make_set(Location), LocationCount=dcount(Location) by UserPrincipalName, bin(TimeGenerated, 1h) | where LocationCount > 1 | sort by TimeGenerated desc # New app consent granted AuditLogs | where OperationName == "Consent to application" | extend InitiatedBy = tostring(InitiatedBy.user.userPrincipalName) | extend AppName = tostring(TargetResources[0].displayName) | project TimeGenerated, InitiatedBy, AppName, OperationName # Service principal credential added AuditLogs | where OperationName has "Add service principal credentials" | extend Actor = tostring(InitiatedBy.user.userPrincipalName) | extend TargetSP = tostring(TargetResources[0].displayName) | project TimeGenerated, Actor, TargetSP, OperationName # Global Admin role assignment AuditLogs | where OperationName == "Add member to role" | extend RoleName = tostring(TargetResources[0].displayName) | where RoleName == "Global Administrator" | extend AddedUser = tostring(TargetResources[2].userPrincipalName) | extend Actor = tostring(InitiatedBy.user.userPrincipalName) | project TimeGenerated, Actor, AddedUser, RoleName # Conditional Access policy changes AuditLogs | where OperationName has "conditional access policy" | extend Actor = tostring(InitiatedBy.user.userPrincipalName) | extend PolicyName = tostring(TargetResources[0].displayName) | project TimeGenerated, Actor, OperationName, PolicyName # MFA bypass attempts SigninLogs | where AuthenticationRequirement == "multiFactorAuthentication" | where ResultType != "0" | summarize Count=count() by UserPrincipalName, ResultDescription | sort by Count desc # Azure resource deletion (sabotage detection) AzureActivity | where OperationNameValue has "delete" | where ActivityStatusValue == "Success" | summarize DeleteCount=count() by Caller, bin(TimeGenerated, 1h) | where DeleteCount > 5 | sort by DeleteCount desc # Key Vault access anomalies AzureDiagnostics | where ResourceProvider == "MICROSOFT.KEYVAULT" | where OperationName == "SecretGet" | summarize Count=count() by CallerIPAddress, identity_claim_upn_s, bin(TimeGenerated, 1h) | where Count > 20 # Detect diagnostic settings deletion (defense evasion) AzureActivity | where OperationNameValue == "MICROSOFT.INSIGHTS/DIAGNOSTICSETTINGS/DELETE" | project TimeGenerated, Caller, ResourceGroup, OperationNameValue
CREDENTIAL THEFT DETECTION PATTERNS#
# AWS - Access key used from unusual IP
# Baseline normal IPs for each access key, alert on new ones
SELECT useridentity.accesskeyid, sourceipaddress, COUNT(*) as call_count
FROM cloudtrail_logs
WHERE eventtime > '2026-03-12'
GROUP BY useridentity.accesskeyid, sourceipaddress;
# AWS - Root account usage (should almost never happen)
SELECT eventtime, eventname, sourceipaddress
FROM cloudtrail_logs
WHERE useridentity.type = 'Root'
ORDER BY eventtime DESC;
# Azure - Token replay detection
SigninLogs
| where TokenIssuerType == "AzureAD"
| where RiskLevelDuringSignIn in ("high", "medium")
| where RiskDetail has "tokenIssuerAnomaly"
# Azure - Credential harvesting from Key Vault
AzureDiagnostics
| where ResourceProvider == "MICROSOFT.KEYVAULT"
| where OperationName in ("SecretGet", "SecretList", "CertificateGet")
| summarize Operations=count() by CallerIPAddress, bin(TimeGenerated, 15m)
| where Operations > 50
PERSISTENCE DETECTION PATTERNS#
# AWS - New IAM user with console access
SELECT eventtime, useridentity.arn, requestparameters
FROM cloudtrail_logs
WHERE eventname IN ('CreateUser', 'CreateLoginProfile', 'CreateAccessKey')
ORDER BY eventtime DESC;
# AWS - Lambda backdoor (new function or updated code)
SELECT eventtime, useridentity.arn, requestparameters, sourceipaddress
FROM cloudtrail_logs
WHERE eventname IN ('CreateFunction20150331', 'UpdateFunctionCode20150331v2')
ORDER BY eventtime DESC;
# Azure - New service principal credentials
AuditLogs
| where OperationName has_any ("Add service principal credentials", "Update application")
| where TargetResources has "KeyDescription"
| project TimeGenerated, InitiatedBy, TargetResources
# Azure - Federation trust modification
AuditLogs
| where OperationName has "Set federation settings on domain"
| project TimeGenerated, InitiatedBy, TargetResources
EXFILTRATION DETECTION PATTERNS#
# AWS - S3 bucket policy made public
SELECT eventtime, useridentity.arn, requestparameters
FROM cloudtrail_logs
WHERE eventname IN ('PutBucketPolicy', 'PutBucketAcl')
ORDER BY eventtime DESC;
-- Check requestparameters for "Principal":"*" or AllUsers
# AWS - EBS snapshot shared externally
SELECT eventtime, useridentity.arn, requestparameters
FROM cloudtrail_logs
WHERE eventname = 'ModifySnapshotAttribute'
ORDER BY eventtime DESC;
# AWS - Unusual data transfer volumes
# Correlate with VPC Flow Logs for bytes transferred
SELECT srcaddr, dstaddr, SUM(bytes) as total_bytes
FROM vpc_flow_logs
WHERE dstaddr NOT LIKE '10.%' AND dstaddr NOT LIKE '172.%'
GROUP BY srcaddr, dstaddr
HAVING total_bytes > 1073741824
ORDER BY total_bytes DESC;
# Azure - Mass file download from SharePoint/OneDrive
OfficeActivity
| where Operation in ("FileDownloaded", "FileSyncDownloadedFull")
| summarize DownloadCount=count(), TotalFiles=dcount(OfficeObjectId) by UserId, bin(TimeGenerated, 1h)
| where DownloadCount > 50
# Azure - Storage account key regeneration (precursor to exfil)
AzureActivity
| where OperationNameValue == "MICROSOFT.STORAGE/STORAGEACCOUNTS/REGENERATEKEY/ACTION"
| project TimeGenerated, Caller, ResourceGroup
SOC RESPONSE CHECKLIST#
# When suspicious CloudTrail event detected: # 1. Identify the principal (userIdentity.arn) # 2. Check sourceIPAddress against known ranges # 3. Review userAgent for unusual tools (aws-cli from unexpected locations) # 4. Correlate with GuardDuty findings # 5. Check if access key was recently created # 6. Review all actions by that principal in the time window # 7. Disable compromised credentials immediately aws iam update-access-key --access-key-id <key> --status Inactive --user-name <user> aws iam delete-login-profile --user-name <user> # When suspicious Azure sign-in detected: # 1. Check sign-in logs for the user (location, device, app) # 2. Review audit logs for post-auth activity # 3. Check risky sign-in and risky user reports # 4. Revoke sessions and reset credentials # 5. Review conditional access policy hits # 6. Check for consent grants and app registrations # PowerShell: Revoke-AzureADUserAllRefreshToken -ObjectId <user-object-id>
CLOUDTRAIL & AZURE MONITOR LOG ANALYSIS FOR SOC
=================================================
Source: https://cheatsheet.johlem.net
A practical reference for detecting threats, investigating incidents,
and building detections in AWS CloudTrail and Azure Monitor/Sentinel.
CLOUDTRAIL FUNDAMENTALS
------------------------
# Enable CloudTrail (all regions, management + data events)
aws cloudtrail create-trail \
--name security-trail \
--s3-bucket-name cloudtrail-logs-bucket \
--is-multi-region-trail \
--enable-log-file-validation
aws cloudtrail start-logging --name security-trail
# Query CloudTrail with AWS CLI
aws cloudtrail lookup-events --lookup-attributes AttributeKey=EventName,AttributeValue=ConsoleLogin
# Query with time range
aws cloudtrail lookup-events \
--start-time "2026-03-01T00:00:00Z" \
--end-time "2026-03-19T23:59:59Z" \
--lookup-attributes AttributeKey=EventName,AttributeValue=CreateUser
# Query by username
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=Username,AttributeValue=suspicious-user
# CloudTrail log structure (key fields):
# eventTime, eventName, eventSource, awsRegion
# sourceIPAddress, userAgent
# userIdentity.type, userIdentity.arn, userIdentity.accountId
# requestParameters, responseElements
# errorCode, errorMessage
CRITICAL CLOUDTRAIL EVENTS TO MONITOR
---------------------------------------
# AUTHENTICATION & ACCESS
ConsoleLogin # Console sign-in (check MFA, sourceIP)
ConsoleLoginFailure # Failed console login
SwitchRole # User assumed another role
GetSessionToken # Temporary credentials requested
GetFederationToken # Federated access token created
AssumeRole # Role assumption
AssumeRoleWithSAML # SAML-based federation
AssumeRoleWithWebIdentity # Web identity federation
# USER & CREDENTIAL MANAGEMENT
CreateUser # New IAM user created
CreateLoginProfile # Console password set for user
CreateAccessKey # New access key pair created
UpdateLoginProfile # Password changed
DeleteUser # User deletion (covering tracks)
AddUserToGroup # Group membership change
AttachUserPolicy # Direct policy attachment
# POLICY & PERMISSION CHANGES
CreatePolicy # New IAM policy created
CreatePolicyVersion # Policy updated (check for wildcards)
AttachRolePolicy # Policy attached to role
PutRolePolicy # Inline policy added to role
PutUserPolicy # Inline policy added to user
AttachGroupPolicy # Policy attached to group
# PERSISTENCE MECHANISMS
CreateRole # New role created
UpdateAssumeRolePolicy # Trust policy modified
CreateServiceLinkedRole # Service-linked role created
CreateInstanceProfile # EC2 instance profile created
AddRoleToInstanceProfile # Role added to instance profile
# DEFENSE EVASION
StopLogging # CloudTrail logging stopped *** HIGH PRIORITY ***
DeleteTrail # CloudTrail trail deleted *** HIGH PRIORITY ***
UpdateTrail # Trail configuration changed
PutEventSelectors # Event filtering changed
DisableRule # CloudWatch/EventBridge rule disabled
DeleteFlowLogs # VPC flow logs deleted
DeleteDetector # GuardDuty disabled
# DATA EXFILTRATION INDICATORS
GetObject # S3 object downloaded (data events)
PutBucketPolicy # Bucket policy changed (may allow public)
PutBucketAcl # Bucket ACL changed
CreateSnapshot # EBS snapshot (data theft)
ModifySnapshotAttribute # Snapshot shared externally
ModifyImageAttribute # AMI shared externally
CopySnapshot # Cross-region/account snapshot copy
AuthorizeSecurityGroupIngress # Firewall opened
# RESOURCE CREATION (CRYPTOMINING / ABUSE)
RunInstances # EC2 instances launched
CreateFunction # Lambda function created
CreateStack # CloudFormation stack deployed
ATHENA QUERIES FOR CLOUDTRAIL
------------------------------
# Create Athena table for CloudTrail
CREATE EXTERNAL TABLE cloudtrail_logs (
eventversion STRING, useridentity STRUCT<type:STRING,principalid:STRING,arn:STRING,accountid:STRING>,
eventtime STRING, eventsource STRING, eventname STRING, awsregion STRING,
sourceipaddress STRING, useragent STRING, requestparameters STRING,
responseelements STRING, errorcode STRING, errormessage STRING
) ROW FORMAT SERDE 'org.apache.hive.hcatalog.data.JsonSerDe'
LOCATION 's3://cloudtrail-bucket/AWSLogs/<account-id>/CloudTrail/';
# Failed console logins
SELECT eventtime, useridentity.arn, sourceipaddress, errormessage
FROM cloudtrail_logs
WHERE eventname = 'ConsoleLogin' AND errorcode = 'Failed'
ORDER BY eventtime DESC LIMIT 100;
# Access key creation
SELECT eventtime, useridentity.arn, requestparameters, sourceipaddress
FROM cloudtrail_logs
WHERE eventname = 'CreateAccessKey'
ORDER BY eventtime DESC;
# CloudTrail tampering
SELECT eventtime, useridentity.arn, eventname, sourceipaddress
FROM cloudtrail_logs
WHERE eventname IN ('StopLogging', 'DeleteTrail', 'UpdateTrail', 'PutEventSelectors')
ORDER BY eventtime DESC;
# Unusual AssumeRole activity
SELECT eventtime, useridentity.arn, requestparameters, sourceipaddress
FROM cloudtrail_logs
WHERE eventname = 'AssumeRole'
AND sourceipaddress NOT LIKE '10.%'
ORDER BY eventtime DESC LIMIT 200;
# S3 data exfiltration (large number of GetObject calls)
SELECT useridentity.arn, COUNT(*) as get_count, MIN(eventtime) as first_seen, MAX(eventtime) as last_seen
FROM cloudtrail_logs
WHERE eventname = 'GetObject'
GROUP BY useridentity.arn
HAVING COUNT(*) > 100
ORDER BY get_count DESC;
AZURE ACTIVITY LOG KEY EVENTS
-------------------------------
# HIGH PRIORITY EVENTS
# Authentication
"Sign-in activity" # Azure AD sign-in logs
"Risky sign-in" # Identity Protection alerts
"MFA denied" # Blocked MFA attempt
"User registered security info" # MFA registration
"Consent to application" # OAuth consent grant
# Role & Permission Changes
"Add member to role" # Role assignment
"Add eligible member to role in PIM" # PIM role activation
"Remove member from role" # Role removal
"Add role assignment" # Azure RBAC change
# User & Group Management
"Add user" # New user created
"Delete user" # User deleted
"Update user" # User properties changed
"Add member to group" # Group membership
"Add owner to group" # Group ownership
"Reset user password" # Password reset
"Invite external user" # Guest user invited
# Application & Service Principal
"Add application" # App registration
"Add service principal" # Service principal created
"Add service principal credentials" # Secret/cert added
"Consent to application" # App consent granted
"Add app role assignment to service principal" # API permissions granted
"Add owner to application" # App ownership changed
# Subscription & Resource
"Create or Update Virtual Machine" # VM creation
"Create role assignment" # RBAC assignment
"Delete resource group" # Resource deletion
"Create or Update Network Security Group" # NSG changes
"Delete Network Security Group Rule" # Firewall rule removed
# Defense Evasion
"Delete diagnostic setting" # Logging disabled
"Update diagnostic setting" # Logging modified
"Deletes the activity log profile" # Activity log export removed
KQL QUERIES FOR MICROSOFT SENTINEL
------------------------------------
# Failed sign-ins with high volume (brute force)
SigninLogs
| where ResultType != "0"
| summarize FailedCount=count(), DistinctUsers=dcount(UserPrincipalName) by IPAddress, bin(TimeGenerated, 1h)
| where FailedCount > 20
| sort by FailedCount desc
# Successful login after multiple failures (credential stuffing success)
let FailedLogins = SigninLogs
| where ResultType != "0"
| summarize FailCount=count() by UserPrincipalName, IPAddress
| where FailCount > 5;
SigninLogs
| where ResultType == "0"
| join kind=inner FailedLogins on UserPrincipalName, IPAddress
| project TimeGenerated, UserPrincipalName, IPAddress, AppDisplayName, FailCount
# Impossible travel detection
SigninLogs
| where ResultType == "0"
| summarize Locations=make_set(Location), LocationCount=dcount(Location) by UserPrincipalName, bin(TimeGenerated, 1h)
| where LocationCount > 1
| sort by TimeGenerated desc
# New app consent granted
AuditLogs
| where OperationName == "Consent to application"
| extend InitiatedBy = tostring(InitiatedBy.user.userPrincipalName)
| extend AppName = tostring(TargetResources[0].displayName)
| project TimeGenerated, InitiatedBy, AppName, OperationName
# Service principal credential added
AuditLogs
| where OperationName has "Add service principal credentials"
| extend Actor = tostring(InitiatedBy.user.userPrincipalName)
| extend TargetSP = tostring(TargetResources[0].displayName)
| project TimeGenerated, Actor, TargetSP, OperationName
# Global Admin role assignment
AuditLogs
| where OperationName == "Add member to role"
| extend RoleName = tostring(TargetResources[0].displayName)
| where RoleName == "Global Administrator"
| extend AddedUser = tostring(TargetResources[2].userPrincipalName)
| extend Actor = tostring(InitiatedBy.user.userPrincipalName)
| project TimeGenerated, Actor, AddedUser, RoleName
# Conditional Access policy changes
AuditLogs
| where OperationName has "conditional access policy"
| extend Actor = tostring(InitiatedBy.user.userPrincipalName)
| extend PolicyName = tostring(TargetResources[0].displayName)
| project TimeGenerated, Actor, OperationName, PolicyName
# MFA bypass attempts
SigninLogs
| where AuthenticationRequirement == "multiFactorAuthentication"
| where ResultType != "0"
| summarize Count=count() by UserPrincipalName, ResultDescription
| sort by Count desc
# Azure resource deletion (sabotage detection)
AzureActivity
| where OperationNameValue has "delete"
| where ActivityStatusValue == "Success"
| summarize DeleteCount=count() by Caller, bin(TimeGenerated, 1h)
| where DeleteCount > 5
| sort by DeleteCount desc
# Key Vault access anomalies
AzureDiagnostics
| where ResourceProvider == "MICROSOFT.KEYVAULT"
| where OperationName == "SecretGet"
| summarize Count=count() by CallerIPAddress, identity_claim_upn_s, bin(TimeGenerated, 1h)
| where Count > 20
# Detect diagnostic settings deletion (defense evasion)
AzureActivity
| where OperationNameValue == "MICROSOFT.INSIGHTS/DIAGNOSTICSETTINGS/DELETE"
| project TimeGenerated, Caller, ResourceGroup, OperationNameValue
CREDENTIAL THEFT DETECTION PATTERNS
-------------------------------------
# AWS - Access key used from unusual IP
# Baseline normal IPs for each access key, alert on new ones
SELECT useridentity.accesskeyid, sourceipaddress, COUNT(*) as call_count
FROM cloudtrail_logs
WHERE eventtime > '2026-03-12'
GROUP BY useridentity.accesskeyid, sourceipaddress;
# AWS - Root account usage (should almost never happen)
SELECT eventtime, eventname, sourceipaddress
FROM cloudtrail_logs
WHERE useridentity.type = 'Root'
ORDER BY eventtime DESC;
# Azure - Token replay detection
SigninLogs
| where TokenIssuerType == "AzureAD"
| where RiskLevelDuringSignIn in ("high", "medium")
| where RiskDetail has "tokenIssuerAnomaly"
# Azure - Credential harvesting from Key Vault
AzureDiagnostics
| where ResourceProvider == "MICROSOFT.KEYVAULT"
| where OperationName in ("SecretGet", "SecretList", "CertificateGet")
| summarize Operations=count() by CallerIPAddress, bin(TimeGenerated, 15m)
| where Operations > 50
PERSISTENCE DETECTION PATTERNS
-------------------------------
# AWS - New IAM user with console access
SELECT eventtime, useridentity.arn, requestparameters
FROM cloudtrail_logs
WHERE eventname IN ('CreateUser', 'CreateLoginProfile', 'CreateAccessKey')
ORDER BY eventtime DESC;
# AWS - Lambda backdoor (new function or updated code)
SELECT eventtime, useridentity.arn, requestparameters, sourceipaddress
FROM cloudtrail_logs
WHERE eventname IN ('CreateFunction20150331', 'UpdateFunctionCode20150331v2')
ORDER BY eventtime DESC;
# Azure - New service principal credentials
AuditLogs
| where OperationName has_any ("Add service principal credentials", "Update application")
| where TargetResources has "KeyDescription"
| project TimeGenerated, InitiatedBy, TargetResources
# Azure - Federation trust modification
AuditLogs
| where OperationName has "Set federation settings on domain"
| project TimeGenerated, InitiatedBy, TargetResources
EXFILTRATION DETECTION PATTERNS
---------------------------------
# AWS - S3 bucket policy made public
SELECT eventtime, useridentity.arn, requestparameters
FROM cloudtrail_logs
WHERE eventname IN ('PutBucketPolicy', 'PutBucketAcl')
ORDER BY eventtime DESC;
-- Check requestparameters for "Principal":"*" or AllUsers
# AWS - EBS snapshot shared externally
SELECT eventtime, useridentity.arn, requestparameters
FROM cloudtrail_logs
WHERE eventname = 'ModifySnapshotAttribute'
ORDER BY eventtime DESC;
# AWS - Unusual data transfer volumes
# Correlate with VPC Flow Logs for bytes transferred
SELECT srcaddr, dstaddr, SUM(bytes) as total_bytes
FROM vpc_flow_logs
WHERE dstaddr NOT LIKE '10.%' AND dstaddr NOT LIKE '172.%'
GROUP BY srcaddr, dstaddr
HAVING total_bytes > 1073741824
ORDER BY total_bytes DESC;
# Azure - Mass file download from SharePoint/OneDrive
OfficeActivity
| where Operation in ("FileDownloaded", "FileSyncDownloadedFull")
| summarize DownloadCount=count(), TotalFiles=dcount(OfficeObjectId) by UserId, bin(TimeGenerated, 1h)
| where DownloadCount > 50
# Azure - Storage account key regeneration (precursor to exfil)
AzureActivity
| where OperationNameValue == "MICROSOFT.STORAGE/STORAGEACCOUNTS/REGENERATEKEY/ACTION"
| project TimeGenerated, Caller, ResourceGroup
SOC RESPONSE CHECKLIST
-----------------------
# When suspicious CloudTrail event detected:
# 1. Identify the principal (userIdentity.arn)
# 2. Check sourceIPAddress against known ranges
# 3. Review userAgent for unusual tools (aws-cli from unexpected locations)
# 4. Correlate with GuardDuty findings
# 5. Check if access key was recently created
# 6. Review all actions by that principal in the time window
# 7. Disable compromised credentials immediately
aws iam update-access-key --access-key-id <key> --status Inactive --user-name <user>
aws iam delete-login-profile --user-name <user>
# When suspicious Azure sign-in detected:
# 1. Check sign-in logs for the user (location, device, app)
# 2. Review audit logs for post-auth activity
# 3. Check risky sign-in and risky user reports
# 4. Revoke sessions and reset credentials
# 5. Review conditional access policy hits
# 6. Check for consent grants and app registrations
# PowerShell: Revoke-AzureADUserAllRefreshToken -ObjectId <user-object-id>
Defensive reference on CyberRamen. Offensive / red-team sheets live on OffensiveRamen.com.