Query Details
let _AWSAccounts =
_GetWatchlist("AccountId-AuditAWSAccounts")
| project RecipientAccountId = AccountId, RecipientAccountName = AccountName
;
union
(
AWSCloudTrail
| where EventName in ("ProvisionProduct", "UpdateProvisionedProduct")
| extend
DynamicResponseElements = todynamic(ResponseElements),
DynamicRequestParameters = todynamic(RequestParameters)
| where tostring(DynamicResponseElements["recordDetail"]["provisionedProductType"]) has "ACCOUNT"
| mv-apply ProvisioningParameter = DynamicRequestParameters["provisioningParameters"] on (
summarize ProvisioningParameters = make_bag(bag_pack(tostring(ProvisioningParameter["key"]), ProvisioningParameter["value"]))
)
| extend
Status = tostring(DynamicResponseElements["recordDetail"]["status"]),
ProvisionedProductId = tostring(DynamicResponseElements["recordDetail"]["provisionedProductId"]),
AccountName = tostring(ProvisioningParameters["AccountName"]),
ManagedOrganizationalUnit = tostring(split(tostring(ProvisioningParameters["ManagedOrganizationalUnit"]), " ")[0]),
AccountEmail = tostring(ProvisioningParameters["AccountEmail"]),
SSOUserEmail = tostring(ProvisioningParameters["SSOUserEmail"])
),
(
AWSCloudTrail
| where EventTypeName == "AwsApiCall" and EventName in ("CreateManagedAccount")//, "UpdateManagedAccount")
| extend DynamicRequestParameters = todynamic(RequestParameters)
| extend
ProvisionedProductId = tostring(DynamicRequestParameters["provisionedProductId"]),
AccountName = tostring(DynamicRequestParameters["accountName"]),
ManagedOrganizationalUnit = tostring(split(tostring(DynamicRequestParameters["parentOrganizationalUnitName"]), " ")[0]),
AccountId = tostring(DynamicRequestParameters["accountId"])
)
| summarize
StartTime = min(TimeGenerated),
EndTime = max(TimeGenerated),
take_any(UserIdentityType),
//take_any(UserIdentityPrincipalid),
take_any(UserIdentityArn),
take_any(UserIdentityAccountId),
take_any(UserIdentityUserName),
take_any(SessionIssuerAccountId),
take_any(SessionIssuerUserName),
SourceIPAddresses = array_sort_asc(make_set_if(SourceIpAddress, not(SourceIpAddress has_any (".amazonaws.com", "AWS Internal")))),
EventSource = array_sort_asc(make_set(EventSource)),
EventName = array_sort_asc(make_set(EventName)),
take_any(AWSRegion),
take_any(Status),
arg_max(TimeGenerated, ManagedOrganizationalUnit),
take_any(AccountId),
take_any(ProvisionedProductId),
UserAgent = array_sort_asc(make_set_if(UserAgent, not(SourceIpAddress has_any (".amazonaws.com", "AWS Internal"))))
by UserIdentityPrincipalid, RecipientAccountId, AccountName
| where EventName has "ProvisionProduct"
| lookup kind=leftouter (
AWSCloudTrail
| where EventName in ("CreateManagedAccount", "UpdateManagedAccount") and EventTypeName == "AwsServiceEvent"
| extend DynamicServiceEventDetails = todynamic(ServiceEventDetails)
| extend ServiceEventDetailsKey = tostring(bag_keys(DynamicServiceEventDetails)[0])
| project
TimeGenerated,
ServiceEventDetails,
AccountName = tostring(DynamicServiceEventDetails[ServiceEventDetailsKey]["account"]["accountName"]),
ManagedOrganizationalUnit = tostring(DynamicServiceEventDetails[ServiceEventDetailsKey]["organizationalUnit"]["organizationalUnitName"]),
AccountId = tostring(DynamicServiceEventDetails[ServiceEventDetailsKey]["account"]["accountId"])
| summarize arg_max(TimeGenerated, *) by AccountName, AccountId
| project-away TimeGenerated
) on AccountName
| extend AccountId = coalesce(AccountId1, AccountId)
| lookup kind=leftouter _AWSAccounts on RecipientAccountId
| project
StartTime,
EndTime,
RecipientAccountId,
RecipientAccountName,
UserIdentityType,
UserIdentityPrincipalid,
UserIdentityArn,
UserIdentityAccountId,
UserIdentityUserName,
SessionIssuerAccountId,
SessionIssuerUserName,
SourceIPAddresses,
EventSource,
EventName,
Status,
ManagedOrganizationalUnit,
AccountName,
AccountId,
ProvisionedProductId,
AWSRegion,
ServiceEventDetails,
UserAgent
The query retrieves information about AWS accounts and their provisioning activities. It combines data from two sources, AWSCloudTrail and a watchlist called "AccountId-AuditAWSAccounts".
The query filters events related to provisioning products and updates, as well as events related to creating and updating managed accounts. It extracts relevant information such as account name, provisioning parameters, status, provisioned product ID, managed organizational unit, account email, and SSO user email.
The query then summarizes the data by various fields such as start time, end time, user identity, source IP addresses, event source, event name, status, managed organizational unit, account ID, provisioned product ID, AWS region, service event details, and user agent. It also performs lookups to enrich the data with additional information from the watchlist.
The final result includes the summarized information for each account, including the start and end times of the provisioning activities, recipient account ID and name, user identity details, source IP addresses, event details, status, managed organizational unit, account name, account ID, provisioned product ID, AWS region, service event details, and user agent.

Jose Sebastián Canós
Released: August 4, 2023
Tables
Keywords
Operators