text code block:from logs-aws.cloudtrail-* METADATA _id, _version, _index // filter for GetServiceQuota API calls | where event.dataset == "aws.cloudtrail" and event.provider == "servicequotas.amazonaws.com" and event.action == "GetServiceQuota" // truncate the timestamp to a 30-second window | eval Esql.time_window_date_trunc = date_trunc(30 seconds, @timestamp) // dissect request parameters to extract service and quota code | dissect aws.cloudtrail.request_parameters "{%{?Esql.aws_cloudtrail_request_parameters_service_code_key}=%{Esql.aws_cloudtrail_request_parameters_service_code}, %{?quota_code_key}=%{Esql.aws_cloudtrail_request_parameters_quota_code}}" // filter for EC2 service quota L-1216C47A (vCPU on-demand instances) | where Esql.aws_cloudtrail_request_parameters_service_code == "ec2" and Esql.aws_cloudtrail_request_parameters_quota_code == "L-1216C47A" // keep only the relevant fields | keep Esql.time_window_date_trunc, aws.cloudtrail.user_identity.arn, cloud.region, Esql.aws_cloudtrail_request_parameters_service_code, Esql.aws_cloudtrail_request_parameters_quota_code, aws.cloudtrail.request_parameters, @timestamp, aws.cloudtrail.user_identity.type, aws.cloudtrail.user_identity.access_key_id, source.ip, cloud.account.id, user_agent.original, source.as.organization.name, data_stream.namespace // count the number of unique regions and total API calls within the time window | stats Esql.cloud_region_count_distinct = count_distinct(cloud.region), Esql.event_count = count(*), Esql.aws_cloudtrail_request_parameters_values = VALUES(aws.cloudtrail.request_parameters), Esql.event_timestamp_values = VALUES(@timestamp), Esql.aws_cloudtrail_user_identity_type_values = VALUES(aws.cloudtrail.user_identity.type), Esql.aws_cloudtrail_user_identity_access_key_id_values = VALUES(aws.cloudtrail.user_identity.access_key_id), Esql.source_ip_values = VALUES(source.ip), Esql.cloud_account_id_values = VALUES(cloud.account.id), Esql.user_agent_original_values = VALUES(user_agent.original), Esql.source_as_organization_name_values = VALUES(source.as.organization.name), Esql.cloud_region_values = VALUES(cloud.region), Esql.data_stream_namespace_values = VALUES(data_stream.namespace) by Esql.time_window_date_trunc, aws.cloudtrail.user_identity.arn // filter for API calls in more than 10 regions within the 30-second window | where Esql.cloud_region_count_distinct >= 10 and Esql.event_count >= 10
Install detection rules in Elastic Security
Detect AWS Service Quotas Multi-Region GetServiceQuota Requests in the Elastic Security detection engine by installing this rule into your Elastic Stack.
To setup this rule, check out the installation guide for Prebuilt Security Detection Rules(external, opens in a new tab or window).