Query Details

AWS Cloud Trail Aws Iam Accessdenied Discovery Events

Query

let query_frequency = 1h;
let query_period = 2h;
let threshold = 5;
let _ExpectedErrorCodes = dynamic(["AccessDenied", "InvalidAccessException", "Client.UnauthorizedOperation", "AuthorizerConfigurationException"]);
let _ExpectedRoleIdentityRegex = toscalar(
    _GetWatchlist("Activity-ExpectedSignificantActivity")
    | where Activity == "AWSAssumedRoleIdentityEventName_Regex" and Auxiliar has_any (_ExpectedErrorCodes)
    | summarize RegEx = make_set(strcat(SourceResource, ActorPrincipalName))
    | extend RegEx = strcat(@"^(", strcat_array(RegEx, "|"), @")$")
);
let _ExpectedUsers = toscalar(
    _GetWatchlist("Activity-ExpectedSignificantActivity")
    | where Activity == "AWSIAMUser" and Auxiliar has_any (_ExpectedErrorCodes)
    | summarize make_list(ActorPrincipalName)
);
let _ExpectedIPAddresses = toscalar(
    _GetWatchlist("IP-Vendors")
    | where Notes has "[Proxy]"
    | summarize make_list(IPAddress)
);
AWSCloudTrail
| where TimeGenerated > ago(query_period)
| where ErrorCode in ("AccessDenied", "InvalidAccessException", "Client.UnauthorizedOperation", "AuthorizerConfigurationException")
| where not(UserIdentityArn in (_ExpectedUsers))
| extend UserIdentityUserName = tostring(split(UserIdentityPrincipalid, ":")[1])
| where not(ErrorCode in (_ExpectedErrorCodes) and strcat(SessionIssuerUserName, UserIdentityUserName) matches regex _ExpectedRoleIdentityRegex)
| summarize arg_min(TimeGenerated, *) by UserIdentityArn, EventName, ErrorCode
| as _Events
| join kind=leftsemi (
    _Events
    // query_period should be 2 * query_frequency
    | evaluate activity_counts_metrics(Type, TimeGenerated, ago(query_period), now(), query_frequency, UserIdentityArn)
    | summarize
        arg_min(PreviousTimeGenerated = TimeGenerated, PreviousCount = ["count"]),
        arg_max(CurrentTimeGenerated = TimeGenerated, CurrentCount = ["count"])
        by UserIdentityArn
    | where CurrentTimeGenerated > ago(query_period)
    | extend PreviousCount = iff(PreviousTimeGenerated == CurrentTimeGenerated, 0, PreviousCount)
    | where (not(PreviousCount > threshold) and CurrentCount > threshold)
        or ((CurrentCount - PreviousCount) > threshold)
    ) on UserIdentityArn
| where not(isnotempty(parse_ipv4(SourceIpAddress)) and ipv4_is_in_any_range(SourceIpAddress, _ExpectedIPAddresses))
| invoke AWSIdentityRole()
| project
    TimeGenerated,
    UserIdentityType,
    Identity,
    ActorRole,
    UserIdentityAccountId,
    UserIdentityAccountName,
    RecipientAccountId,
    RecipientAccountName,
    AWSRegion,
    SessionCreationDate,
    UserIdentityPrincipalid,
    UserIdentityArn,
    SourceIpAddress,
    EventSource,
    EventTypeName,
    EventName,
    ManagementEvent,
    ReadOnly,
    ErrorCode,
    ErrorMessage,
    RequestParameters,
    ResponseElements,
    Resources,
    SessionMfaAuthenticated,
    UserAgent,
    AwsEventId

Explanation

This KQL query is designed to monitor and identify unusual or unauthorized access attempts in AWS CloudTrail logs. Here's a simplified breakdown of what the query does:

  1. Set Parameters: It defines some parameters like query_frequency, query_period, and threshold to control the time intervals and thresholds for detecting unusual activities.

  2. Define Expected Values: It retrieves expected error codes, role identities, users, and IP addresses from watchlists. These are used to filter out known and expected activities.

  3. Filter CloudTrail Logs: It looks at AWS CloudTrail logs from the last 2 hours (query_period) and filters for specific error codes that indicate access issues (e.g., "AccessDenied").

  4. Exclude Expected Activities: The query excludes activities from known users, roles, and IP addresses that match the expected patterns, focusing on unexpected or unauthorized activities.

  5. Identify Unusual Activity: It checks for users whose activity count has increased significantly (beyond a defined threshold) compared to the previous period.

  6. Filter by IP Address: It further filters out activities from known proxy IP addresses.

  7. Invoke Additional Role Information: It calls a function (AWSIdentityRole) to get more details about the roles involved in the activities.

  8. Select Relevant Data: Finally, it selects and projects relevant fields from the logs to provide a detailed view of the suspicious activities, including user identity, event details, and error information.

In summary, this query is used to detect and report on potentially unauthorized or suspicious access attempts in AWS by filtering out known and expected activities and focusing on anomalies.

Details

Jose Sebastián Canós profile picture

Jose Sebastián Canós

Released: March 11, 2024

Tables

_GetWatchlistAWSCloudTrail

Keywords

AWSCloudTrailDevicesUserIPAddressesEventNameErrorCodeUserIdentityArnAWSRegionSessionCreationDateEventSourceEventTypeNameManagementEventReadOnlyErrorMessageRequestParametersResponseElementsResourcesSessionMfaAuthenticatedUserAgentAwsEventId

Operators

lettoscalardynamicagoinhas_anysummarizemake_setstrcatstrcat_arraymake_listwhereextendtostringsplitmatchesregexarg_minbyasjoinkindleftsemievaluateactivity_counts_metricsnowiffisnotemptyparse_ipv4ipv4_is_in_any_rangeinvokeproject

Actions