Analytics AWS Identity Role
Query
// This will have to be updated after 13th January 2025 - https://aws.amazon.com/es/blogs/security/modifications-to-aws-cloudtrail-event-data-of-iam-identity-center/
let _AWSAccounts = _GetWatchlist("AccountId-AuditAWSAccounts");
T
| extend
RecipientAccountId = column_ifexists("RecipientAccountId", ""),
UserIdentityAccountId = column_ifexists("UserIdentityAccountId", ""),
UserIdentityType = column_ifexists("UserIdentityType", ""),
UserIdentityPrincipalid = column_ifexists("UserIdentityPrincipalid", ""),
UserIdentityArn = column_ifexists("UserIdentityArn", ""),
SessionIssuerType = column_ifexists("SessionIssuerType", ""),
EventName = column_ifexists("EventName", ""),
RequestParameters = column_ifexists("RequestParameters", ""),
UserIdentityInvokedBy = column_ifexists("UserIdentityInvokedBy", ""),
UserIdentityUserName = column_ifexists("UserIdentityUserName", ""),
UserIdentityAccessKeyId = column_ifexists("UserIdentityAccessKeyId", ""),
SessionIssuerUserName = column_ifexists("SessionIssuerUserName", ""),
AdditionalEventData = column_ifexists("AdditionalEventData", ""),
ErrorMessage = column_ifexists("ErrorMessage", "")
| lookup (_AWSAccounts | project RecipientAccountId = AccountId, RecipientAccountName = AccountName) on RecipientAccountId
| lookup (_AWSAccounts | project UserIdentityAccountId = AccountId, UserIdentityAccountName = AccountName) on UserIdentityAccountId
| extend
Identity = case(
UserIdentityType == "Root", strcat(coalesce(UserIdentityAccountName, UserIdentityAccountId), ":", extract(@"\:([^\:]+$)", 1, UserIdentityArn)),
UserIdentityType == "IAMUser", strcat(coalesce(UserIdentityAccountName, UserIdentityAccountId), ":", coalesce(extract(@"\:([^\:]+$)", 1, UserIdentityArn), strcat("user/", UserIdentityUserName))),
UserIdentityType == "AssumedRole" and SessionIssuerType in ("", "Role"), strcat(coalesce(UserIdentityAccountName, UserIdentityAccountId), ":", "roleSessionName/", extract(@"\:([^\:]+$)", 1, UserIdentityPrincipalid)),
UserIdentityType == "AWSAccount" and isempty(UserIdentityPrincipalid), strcat(coalesce(UserIdentityAccountName, UserIdentityAccountId), ":"),
UserIdentityType == "AWSAccount" and UserIdentityPrincipalid matches regex @"^[A-Z0-9]{21}$", strcat(coalesce(UserIdentityAccountName, UserIdentityAccountId), ":", UserIdentityPrincipalid),
UserIdentityType == "AWSAccount" and UserIdentityPrincipalid matches regex @"^[A-Z0-9]{21}\:[^\:]+$", strcat(coalesce(UserIdentityAccountName, UserIdentityAccountId), ":", "roleSessionName/", extract(@"\:([^\:]+$)", 1, UserIdentityPrincipalid)),
UserIdentityType == "AWSService", UserIdentityInvokedBy,
UserIdentityType == "SAMLUser" and EventName == "AssumeRoleWithSAML", UserIdentityUserName,
UserIdentityType == "WebIdentityUser" and EventName == "AssumeRoleWithWebIdentity", UserIdentityUserName,
UserIdentityType == "Unknown" and isnotempty(UserIdentityAccountId) and UserIdentityAccountId == UserIdentityPrincipalid, coalesce(UserIdentityAccountName, UserIdentityAccountId),
UserIdentityType == "Unknown" and isnotempty(UserIdentityAccountId) and not(UserIdentityAccountId == UserIdentityPrincipalid), coalesce(UserIdentityUserName, UserIdentityPrincipalid, UserIdentityAccessKeyId),
UserIdentityType == "", coalesce(UserIdentityInvokedBy, extract(@"(.+)\-[a-f0-9]{17}$", 1, tostring(todynamic(RequestParameters)["sessionId"]))),
strcat("UnexpectedUserIdentityType", ":", extract(@"\:([^\:]+$)", 1, UserIdentityPrincipalid))
),
ActorRole = case(
UserIdentityType == "AssumedRole", coalesce(SessionIssuerUserName, extract(@"\:assumed-role\/([^\/]+)\/", 1, UserIdentityArn)),
""
)
| extend
TargetRole = case(
EventName in ("SwitchRole", "ExitRole", "RenewRole") and UserIdentityType == "AssumedRole", ActorRole,
EventName in ("SwitchRole", "ExitRole") and not(UserIdentityType == "AssumedRole"), coalesce(extract(@"\:assumed-role\/([^\/]+)\/", 1, tostring(todynamic(AdditionalEventData)["SwitchFrom"])), extract(@"\/([^\/]+)$", 1, tostring(todynamic(AdditionalEventData)["SwitchTo"]))),
EventName matches regex "^AssumeRole", coalesce(tostring(split(todynamic(RequestParameters)["roleArn"], "/")[-1]), extract(@"AssumeRole\w* on resource\: \S+\/([^\/]+)$", 1, ErrorMessage)),
UserIdentityType == "Unknown" and EventName in ("Federate", "GetRoleCredentials"), tostring(todynamic(ServiceEventDetails)["role_name"]),
""
),
TargetRoleSessionName = case(
EventName matches regex "^AssumeRole", tostring(todynamic(RequestParameters)["roleSessionName"]),
""
)Explanation
This KQL (Kusto Query Language) query is designed to analyze AWS CloudTrail logs, specifically focusing on user identity and role-related events. Here's a simplified explanation of what the query does:
-
Preparation:
- It starts by retrieving a list of AWS account IDs from a watchlist named "AccountId-AuditAWSAccounts". This list is used to map account IDs to account names later in the query.
-
Data Extraction:
- The query extracts various fields from the input data table
T, such asRecipientAccountId,UserIdentityAccountId,UserIdentityType, and others. These fields are extracted using thecolumn_ifexistsfunction, which ensures that the query doesn't fail if a column is missing.
- The query extracts various fields from the input data table
-
Account Mapping:
- It performs two lookups to map
RecipientAccountIdandUserIdentityAccountIdto their respective account names using the previously retrieved watchlist.
- It performs two lookups to map
-
Identity Construction:
- The query constructs a human-readable
Identitystring based on theUserIdentityType. It uses different logic for different identity types (e.g., Root, IAMUser, AssumedRole, etc.) to create a meaningful identifier for the user or role involved in the event.
- The query constructs a human-readable
-
Role Identification:
- It identifies the
ActorRolefor events involving assumed roles, extracting the role name from the session issuer or the user identity ARN.
- It identifies the
-
Target Role and Session Name:
- The query determines the
TargetRoleandTargetRoleSessionNamefor events related to role switching or assuming roles. It uses event names and additional event data to extract this information.
- The query determines the
-
Special Cases:
- The query handles various special cases, such as unknown user identity types or specific event names, to ensure accurate identification and mapping of roles and identities.
Overall, this query is designed to provide insights into AWS identity and access management activities by constructing detailed identity and role information from CloudTrail logs. It is particularly useful for auditing and security analysis purposes. Note that the query includes a comment indicating that it may need to be updated after January 13, 2025, due to potential changes in AWS CloudTrail event data.
Details

Jose Sebastián Canós
Released: November 20, 2024
Tables
Keywords
Operators