AWS Discovery API Calls via CLI from a Single Resource
Detects when a single AWS resource is running multiple read-only, discovery API calls in a 10-second window. This behavior could indicate an actor attempting to discover the AWS infrastructure using compromised credentials or a compromised instance. Adversaries may use this information to identify potential targets for further exploitation or to gain a better understanding of the target's infrastructure.
Rule type: esql
Rule indices:
Rule Severity: low
Risk Score: 21
Runs every:
Searches indices from: now-6m
Maximum alerts per execution: ?
References:
Tags:
- Domain: Cloud
- Data Source: AWS
- Data Source: AWS EC2
- Data Source: AWS IAM
- Data Source: AWS S3
- Data Source: AWS Cloudtrail
- Data Source: AWS RDS
- Data Source: AWS Lambda
- Data Source: AWS STS
- Data Source: AWS KMS
- Data Source: AWS SES
- Data Source: AWS Cloudfront
- Data Source: AWS DynamoDB
- Data Source: AWS Elastic Load Balancing
- Use Case: Threat Detection
- Tactic: Discovery
- Resources: Investigation Guide
Version: ?
Rule authors:
- Elastic
Rule license: Elastic License v2
Disclaimer: This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs.
This rule detects when a single AWS identity executes more than five unique discovery-related API calls (Describe*, List*, Get*, or Generate*) within a 10-second window using the AWS CLI.
High volumes of diverse “read-only” API calls in such a short period can indicate scripted reconnaissance, often an early phase of compromise after credential exposure or access to a compromised EC2 instance.
Identify the actor and session context
- Actor ARN (
aws.cloudtrail.user_identity.arn): Determine which IAM user, role, or service principal performed the actions.- Check whether this identity normally performs enumeration activity or belongs to automation infrastructure.
- Identity type (
Esql.aws_cloudtrail_user_identity_arn_type): Validate if the caller is a human IAM user, assumed role, or federated identity. Unusual types (e.g., temporary credentials from an unfamiliar role) may indicate lateral movement. - Access key (
Esql.aws_cloudtrail_user_identity_access_key_id_values) – Identify which specific access key or temporary credential was used.- If multiple suspicious keys are found, use AWS IAM console or
aws iam list-access-keysto determine when they were last used or rotated.
- If multiple suspicious keys are found, use AWS IAM console or
- Account (
Esql.cloud_account_id_values) – Confirm which AWS account was affected and whether it matches the intended operational context (e.g., production vs. sandbox).
Assess the API call pattern and intent
- Distinct action count (
Esql.event_action_count_distinct): Note how many unique API calls occurred within each 10-second window. Counts far above normal operational baselines may indicate scripted reconnaissance. - API actions (
Esql.event_action_values): Review which discovery APIs were invoked.- Focus on services such as EC2 (
DescribeInstances), IAM (ListRoles,ListAccessKeys), S3 (ListBuckets), and KMS (ListKeys), which adversaries frequently query to map assets.
- Focus on services such as EC2 (
- Service providers (
Esql.event_provider_values): Identify which AWS services were targeted.- Multi-service enumeration (IAM + EC2 + S3) suggests broad discovery rather than a specific diagnostic task.
- Time window (
Esql.time_window_date_trunc): Verify whether activity occurred during normal maintenance windows or outside expected hours.
Analyze the source and origin
- Source IP (
Esql.source_ip_values): Check the originating IPs to determine whether the calls came from a known internal host, an EC2 instance, or an unfamiliar external network.- Compare with known corporate CIDR ranges, VPC flow logs, or guardrail baselines.
- Source organization (
Esql.source_as_organization_name_values): Review the associated ASN or organization.- If the ASN belongs to a commercial ISP or VPN service, investigate possible credential compromise or remote attacker usage.
Correlate with additional events
- Search CloudTrail for the same
aws.cloudtrail.user_identity.arnoraws_cloudtrail_user_identity_access_key_id_valueswithin ±30 minutes.- Look for follow-on actions such as
GetCallerIdentity,AssumeRole,CreateAccessKey, or data access (GetObject,CopySnapshot). - Correlate this enumeration with authentication anomalies or privilege-related findings.
- Look for follow-on actions such as
- Cross-reference
Esql.cloud_account_id_valueswith other alerts for lateral or privilege escalation patterns.
Legitimate, high-frequency API activity may originate from:
- Inventory or compliance automation: Scripts or tools such as AWS Config, Cloud Custodian, or custom CMDB collection performing periodic Describe/List calls.
- Operational monitoring systems: DevOps pipelines, Terraform, or deployment verifiers enumerating resources.
- Security tooling: Security scanners performing asset discovery across services.
Validate by confirming:
- Whether the
aws.cloudtrail.user_identity.arncorresponds to a documented automation or monitoring identity. - That the observed
Esql.event_action_valuesmatch known inventory or cost-reporting workflows. - Timing alignment with approved maintenance schedules.
If the activity is unexpected or originates from unrecognized credentials, follow AWS’s incident-handling guidance:
1. Contain
- Temporarily disable or rotate the access key (
Esql.aws_cloudtrail_user_identity_access_key_id_values) using IAM. - Restrict outbound connectivity for the instance or resource from which the API calls originated.
2. Investigate
- Retrieve full CloudTrail logs for the actor and
Esql.time_window_date_truncinterval. - Identify any subsequent write or privilege-modification actions.
- Review associated IAM policies for excessive permissions.
3. Recover and Harden
- Rotate credentials, enforce MFA on human users, and tighten IAM role trust policies.
- Implement AWS Config rules or SCPs to monitor and restrict large-scale enumeration.
4. Post-Incident Actions
- Document the finding and response in your organization’s IR management system.
- Update detection logic or allow-lists for known benign automation.
- Validate recovery by confirming no new suspicious discovery bursts occur.
- AWS Documentation
- AWS Playbook Resources
from logs-aws.cloudtrail-* metadata _id, _version, _index
// create time window buckets of 10 seconds
| eval Esql.time_window_date_trunc = date_trunc(10 seconds, @timestamp)
| where
event.dataset == "aws.cloudtrail"
// filter on CloudTrail audit logs for IAM, EC2, S3, etc.
and event.provider in (
"iam.amazonaws.com",
"ec2.amazonaws.com",
"s3.amazonaws.com",
"rds.amazonaws.com",
"lambda.amazonaws.com",
"dynamodb.amazonaws.com",
"kms.amazonaws.com",
"cloudfront.amazonaws.com",
"elasticloadbalancing.amazonaws.com",
"cloudtrail.amazonaws.com",
"sts.amazonaws.com",
"ses.amazonaws.com"
)
// ignore AWS service actions
and aws.cloudtrail.user_identity.type != "AWSService"
// filter for aws-cli specifically
and user_agent.name == "aws-cli"
// exclude DescribeCapacityReservations events related to AWS Config
and event.action != "DescribeCapacityReservations"
// filter for Describe, Get, List, and Generate API calls
| where true in (
starts_with(event.action, "Describe"),
starts_with(event.action, "Get"),
starts_with(event.action, "List"),
starts_with(event.action, "Generate")
)
// extract owner, identity type, and actor from the ARN
| dissect aws.cloudtrail.user_identity.arn "%{}::%{Esql_priv.aws_cloudtrail_user_identity_arn_owner}:%{Esql.aws_cloudtrail_user_identity_arn_type}/%{Esql.aws_cloudtrail_user_identity_arn_roles}"
| where starts_with(Esql.aws_cloudtrail_user_identity_arn_roles, "AWSServiceRoleForConfig") != true
// keep relevant fields (preserving ECS fields and computed time window)
| keep
@timestamp,
Esql.time_window_date_trunc,
event.action,
aws.cloudtrail.user_identity.arn,
aws.cloudtrail.user_identity.type,
aws.cloudtrail.user_identity.access_key_id,
source.ip,
cloud.account.id,
event.provider,
user_agent.name,
source.as.organization.name,
cloud.region,
data_stream.namespace
// count the number of unique API calls per time window and actor
| stats
Esql.event_action_count_distinct = count_distinct(event.action),
Esql.event_action_values = VALUES(event.action),
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.event_provider_values = VALUES(event.provider),
Esql.user_agent_name_values = VALUES(user_agent.name),
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 more than 5 unique API calls per 10s window
| where Esql.event_action_count_distinct > 5
Framework: MITRE ATT&CK
Tactic:
- Name: Discovery
- Id: TA0007
- Reference URL: https://attack.mitre.org/tactics/TA0007/
Technique:
- Name: Cloud Infrastructure Discovery
- Id: T1580
- Reference URL: https://attack.mitre.org/techniques/T1580/