Query Details

AWS Cloud Trail Activity With Monitored AWS Role

Query

let query_frequency = 15m;
let query_wait = 15m;
let _MonitoredRoles =
    _GetWatchlist("AccountId-AuditAWSAccounts")
    | where Notes has "[RoleActivity]"
    | project RequestedRole = tostring(Auxiliar), Auditors = tostring(Auditor), AlertSeverity = tostring(Severity)
;
let _AWSAccounts =
    _GetWatchlist("AccountId-AuditAWSAccounts")
    | project AccountId, AccountName
;
union
    (
    AWSCloudTrail
    | where TimeGenerated between (ago(query_frequency + query_wait) .. ago(query_wait))
    | where EventName in ("Federate", "GetRoleCredentials")
    | extend DynamicServiceEventDetails = todynamic(ServiceEventDetails)
    | extend
        RequestedRole = tostring(DynamicServiceEventDetails["role_name"]),
        RequestedRoleAccountId = tostring(DynamicServiceEventDetails["account_id"])
    ),
    (
    AWSCloudTrail
    | where TimeGenerated between (ago(query_frequency + query_wait) .. ago(query_wait))
    | where EventName in ("AssumeRole")
    | extend RoleArn = tostring(todynamic(RequestParameters)["roleArn"])
    | extend
        RequestedRole = tostring(split(RoleArn, "/")[-1]),
        RequestedRoleAccountId = tostring(split(RoleArn, ":")[4])
    )
| lookup kind=inner _MonitoredRoles on RequestedRole
| lookup kind=leftouter (
    _AWSAccounts
    | project RequestedRoleAccountName = AccountName, AccountId
    ) on $left.RequestedRoleAccountId == $right.AccountId
| as _Events
| join kind=leftouter (
    AWSCloudTrail
    | where TimeGenerated > ago(query_frequency + query_wait)
    | where UserIdentityType == "AssumedRole" and not(ReadOnly) and not(EventTypeName == "AwsConsoleSignIn") and UserIdentityArn matches regex toscalar(_Events | summarize 
    strcat(@"(", strcat_array(make_set(regex_quote(RequestedRole)), "|"), @")"))
    | summarize WriteEventNames = make_set(EventName) by UserIdentityArn, SessionIssuerAccountId
    | project
        EventNames_UserIdentityArn = UserIdentityArn,
        EventNames_SessionIssuerAccountId = SessionIssuerAccountId,
        WriteEventNames
) on $left.RequestedRoleAccountId == $right.EventNames_SessionIssuerAccountId
| where isempty(EventNames_SessionIssuerAccountId) or EventNames_UserIdentityArn contains RequestedRole
| project-away EventNames_*
| summarize
    StartTime = min(TimeGenerated),
    EndTime = max(TimeGenerated),
    SourceIpAddresses = array_sort_asc(make_set_if(SourceIpAddress, isnotempty(SourceIpAddress), 100)),
    UserIdentityTypes = array_sort_asc(make_set(UserIdentityType)),
    UserIdentityUserName = take_any(UserIdentityUserName),
    EventNames = array_sort_asc(make_set(EventName)),
    WriteEventNames = array_sort_asc(make_set(WriteEventNames)),
    ReadOnly = make_set_if(ReadOnly, isnotempty(ReadOnly)),
    RequestedRoleAccounts = array_sort_asc(make_set(coalesce(RequestedRoleAccountName, RequestedRoleAccountId))),
    ShareEventIds = array_sort_asc(make_set(SharedEventId)),
    take_any(*)
    by RequestedRole, UserIdentityAccountId, SessionIssuerArn, UserIdentityPrincipalid, EventSource, EventTypeName
| extend Identity = coalesce(UserIdentityUserName, UserIdentityPrincipalid)
| mv-apply
    SourceIpAddress = iff(array_length(SourceIpAddresses) > 0, SourceIpAddresses, dynamic([""])) to typeof(string),
    WriteEventName = iff(array_length(WriteEventNames) > 0, WriteEventNames, dynamic([""])) to typeof(string)
    on (
    summarize
        AddressesList = strcat_array(array_sort_asc(make_set_if(SourceIpAddress, not(isempty(SourceIpAddress) or SourceIpAddress has ".amazonaws.com"))), '\n\n- '),
        WriteEventNamesList = strcat_array(array_sort_asc(make_set_if(WriteEventName, isnotempty(WriteEventName))), '\n\n- ')
    )
| extend AlertDescription = strcat(
    'This rule detects operations of specified roles in AWS accounts.\n\nThe role "',
    RequestedRole,
    '" was used by "',
    Identity,
    '" in the AWS accounts:\n\n- ',
    strcat_array(RequestedRoleAccounts, '\n\n- '),
    '\n\nThe operations were made from the addresses:\n\n- ',
    AddressesList,
    iff(array_length(WriteEventNames) > 0, strcat('\n\nThe role performed the write operations:\n\n- ', WriteEventNamesList), '\n\nThe role has not performed write operations yet.'),
    '\n'
    )
| project
    StartTime,
    EndTime,
    UserIdentityTypes,
    UserIdentityAccountId,
    SessionCreationDate,
    SessionIssuerUserName,
    SessionIssuerPrincipalId,
    SessionIssuerArn,
    UserIdentityUserName,
    UserIdentityPrincipalid,
    UserIdentityArn,
    UserIdentityAccessKeyId,
    Identity,
    SourceIpAddresses,
    EventSource,
    EventTypeName,
    EventNames,
    WriteEventNames,
    RequestedRole,
    RequestedRoleAccounts,
    ManagementEvent,
    ReadOnly,
    ErrorCode,
    ErrorMessage,
    RequestParameters,
    ResponseElements,
    Resources,
    ServiceEventDetails,
    SessionMfaAuthenticated,
    UserAgent,
    AwsEventId,
    ShareEventIds,
    AlertSeverity,
    AlertDescription,
    Auditors

Explanation

This query is designed to monitor specific roles in AWS accounts and detect their usage patterns. Here's a simplified breakdown of what the query does:

  1. Setup and Definitions:

    • It defines two time intervals: query_frequency and query_wait, both set to 15 minutes.
    • It retrieves a list of monitored roles from a watchlist named "AccountId-AuditAWSAccounts" and filters them based on specific notes.
  2. Data Collection:

    • It gathers AWS CloudTrail logs for specific events ("Federate", "GetRoleCredentials", "AssumeRole") within a defined time window.
    • It extracts details such as the requested role and account ID from these logs.
  3. Data Enrichment:

    • It enriches the data by joining it with the monitored roles and AWS accounts information to add context like account names and alert severity.
  4. Event Analysis:

    • It identifies and summarizes write operations performed by assumed roles, excluding read-only and console sign-in events.
    • It checks if these operations are associated with the monitored roles.
  5. Summarization:

    • It summarizes the findings, including the time range of events, source IP addresses, user identity types, event names, and any write operations performed.
    • It constructs a detailed alert description that includes the role used, the identity of the user, the AWS accounts involved, and the operations performed.
  6. Output:

    • The final output includes various details about the events, such as user identity, source IPs, event types, and a descriptive alert message.
    • It also includes information about the severity of the alert and the auditors involved.

In essence, this query is used to track and alert on the usage of specific roles in AWS, providing detailed insights into who used the roles, from where, and what operations were performed.

Details

Jose Sebastián Canós profile picture

Jose Sebastián Canós

Released: February 22, 2024

Tables

AWSCloudTrail

Keywords

AwsAccountsEventsRolesUsers

Operators

lethasprojectunionwherebetweenagoinextendtodynamictostringsplitlookupkindonasjoinmatchesregextoscalarsummarizemake_setproject-awayminmaxarray_sort_ascmake_set_ifisnotemptycoalescetake_anybymv-applyiffarray_lengthdynamictypeofstrcat_arraynotisemptystrcat

Actions

GitHub