text code block:from logs-aws.cloudtrail-* metadata _id, _version, _index // filter for DescribeInstances API calls | where event.dataset == "aws.cloudtrail" and event.provider == "ec2.amazonaws.com" and event.action == "DescribeInstances" // truncate the timestamp to a 30-second window | eval Esql.time_window_date_trunc = date_trunc(30 seconds, @timestamp) // keep only the relevant raw fields | keep Esql.time_window_date_trunc, aws.cloudtrail.user_identity.arn, cloud.region, cloud.account.id, aws.cloudtrail.user_identity.access_key_id, aws.cloudtrail.user_identity.type, user_agent.original, source.as.organization.name, source.ip, @timestamp, data_stream.namespace // count the number of unique regions and total API calls within the 30-second window | stats Esql.cloud_region_count_distinct = count_distinct(cloud.region), Esql.event_count = count(*), 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.user_agent_original_values = VALUES(user_agent.original), Esql.source_as_organization_name_values = VALUES(source.as.organization.name), Esql.cloud_account_id_values = VALUES(cloud.account.id), 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 resources making DescribeInstances 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 EC2 Multi-Region DescribeInstances API Calls 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).