Search for AWS adds nine search commands. Eight of them are generating commands: they start a search (they go first, after the leading |) and produce rows from a live AWS API. The ninth, awsjson, is a streaming formatter you pipe results into.
All eight generating commands require the run_aws_search capability. See Access control.
Conventions shared by all commands
A few arguments and behaviors work the same everywhere, so they are documented once here.
Accounts (account=). Targets the account you registered under that name. account=* fans out to every registered account in parallel. Without account=, the command uses your single registered account (or fans out across all of them when you have several). Every row carries an account field naming the one it came from.
Regions (region=). A region id (us-east-1), or *. Without region=, the command uses the account’s default region. region=* means every region in the account’s allowed-regions list when one is configured; with no list it uses the default region and warns that it did so. A region outside an account’s allowed list is rejected for that account. Every row carries a region field, except the rows of | awscost, which runs once per account; use group_by=REGION there for a regional breakdown. See Accounts.
concurrency= (default 8, ceiling 64) caps how many account and region pairs are queried at once during a fan-out.
cache= overrides the freshness of the on-disk result cache for this search: cache=0 bypasses it and always calls AWS; cache=5m accepts a result up to five minutes old. Each command has its own default. See Concepts - caching.
Time windows (start=, end=). Where a command takes a window, both accept a date (2026-09-01), epoch seconds, or Splunk relative time (-24h, -30d@d, @mon, now). Without them, the command uses the search’s time-range picker where that makes sense (awscost) or a per-command default.
Quote commas. SPL splits an unquoted argument on commas and spaces, so any value that carries a comma or a space must be quoted: dimensions="BucketName=logs,StorageType=StandardStorage", groups="/aws/lambda/a,/aws/lambda/b". The commands reject a stray fragment with an error that shows the quoted form rather than silently dropping it.
Errors are per target. During a fan-out, an account or region whose AWS call fails emits a single row carrying _target_error, and the search continues against the others. A target that fails earlier - its stored secret cannot be read, or its role cannot be assumed - is skipped with a warning in the search’s messages instead of a row, so read the messages as well.
| awsget - list and get resources
Use awsget whenever you would open a service’s console page or run aws <service> describe-*. It lists resources of a kind over the Cloud Control API, or fetches one resource by identifier, and emits one row per resource with its properties as JSON in _raw and as fields.
| awsget kind=<TypeName|alias>
[identifier=<id>] [detail=<bool>] [limit=<int>]
[resource_model=<json>]
[cluster=<arn>] [function_name=<name>] [load_balancer_arn=<arn>]
[rest_api_id=<id>] [route_table_id=<id>] [scope=<REGIONAL|CLOUDFRONT>]
[account=<name|*>] [region=<id|*>] [concurrency=<int>] [cache=<duration>]| Argument | Description |
|---|---|
kind= | Required. A CloudFormation type name (AWS::EC2::Instance, AWS::ECR::Repository, AWS::CloudWatch::Alarm) or one of the aliases below. Any type with a Cloud Control list handler works, including types AWS adds later; a type with no list handler, or a misspelled name, returns a clear error. |
identifier= | Fetch exactly one resource by its primary identifier: a single GetResource, no listing, no parent needed. Quote it - compound identifiers such as an ECS service’s carry a |. |
detail=true | Add a per-resource GetResource call so kinds whose list returns only an identifier (stacks, volumes, security groups, KMS keys, queues, and others) carry their full state. One extra call per resource; cap it with limit=. |
limit= | Cap the number of rows from each account and region. In a fan-out every target returns up to this many, so limit=10 over four regions is up to 40 rows, and with detail=true up to 40 extra calls. |
resource_model= | Raw {"Key":"Value"} JSON for an uncatalogued type whose list handler needs a parent identifier. |
cluster=, function_name=, load_balancer_arn=, rest_api_id=, route_table_id=, scope= | Parent identifiers for the kinds that need one - ECS services, Lambda function URLs and permissions, listeners, API resources, routes, WAF web ACLs. A parent-required kind fails fast with guidance when its parent is missing. |
Key fields on each row: identifier, type (the CloudFormation type name), account, region, the resource’s top-level properties as fields, and _raw with the full JSON (ready for spath).
Aliases. These short names resolve to the type on the right; the type name always works too.
| Alias | Type | Notes |
|---|---|---|
instances, ec2 | AWS::EC2::Instance | State is an object: spath path=State.Name |
vpcs, subnets, security-groups, route-tables, internet-gateways, nat-gateways | AWS::EC2::VPC, Subnet, SecurityGroup, RouteTable, InternetGateway, NatGateway | |
volumes, ebs | AWS::EC2::Volume | |
volume-attachments, eip-associations, vpc-gateway-attachments | AWS::EC2::VolumeAttachment, EIPAssociation, VPCGatewayAttachment | Association kinds - the identifier joins the two sides |
routes | AWS::EC2::Route | Needs route_table_id= |
buckets, s3 | AWS::S3::Bucket | Account-global |
bucket-policies | AWS::S3::BucketPolicy | One read per bucket: identifier=<bucket> |
functions, lambdas | AWS::Lambda::Function | |
event-source-mappings, esm | AWS::Lambda::EventSourceMapping | |
function-urls, event-invoke-configs, lambda-permissions | AWS::Lambda::Url, EventInvokeConfig, Permission | Need function_name= |
roles, users, policies | AWS::IAM::Role, User, ManagedPolicy | Account-global |
dynamodb-tables, ddb | AWS::DynamoDB::Table | |
db-instances, rds and db-clusters, aurora | AWS::RDS::DBInstance, DBCluster | |
ecs-clusters and ecs-services | AWS::ECS::Cluster, Service | Services need cluster= |
eks-clusters, eks | AWS::EKS::Cluster | |
topics, sns and queues, sqs | AWS::SNS::Topic, AWS::SQS::Queue | |
stacks, cfn | AWS::CloudFormation::Stack | StackStatus needs detail=true |
load-balancers, albs and listeners | AWS::ElasticLoadBalancingV2::LoadBalancer, Listener | Listeners need load_balancer_arn= |
log-groups | AWS::Logs::LogGroup | |
rest-apis, http-apis, api-resources | AWS::ApiGateway::RestApi, AWS::ApiGatewayV2::Api, AWS::ApiGateway::Resource | Resources need rest_api_id= |
state-machines, sfn | AWS::StepFunctions::StateMachine | |
kms-keys, kms | AWS::KMS::Key | |
web-acls, waf | AWS::WAFv2::WebACL | Needs scope= |
glue-databases | AWS::Glue::Database | |
hosted-zones | AWS::Route53::HostedZone | Account-global |
kinesis-streams, firehose | AWS::Kinesis::Stream, AWS::KinesisFirehose::DeliveryStream | |
alarms | AWS::CloudWatch::Alarm | |
regions | (synthetic) | The account’s allowed regions, or every region enabled on it via ec2:DescribeRegions; is_default=true marks the default. Feeds the dashboards’ region pickers. |
List Lambda functions in a region:
| awsget kind=lambdas region=us-east-1
| table FunctionName Runtime MemorySize TimeoutStack health (StackStatus is only present with detail=true):
| awsget kind=stacks detail=true region=us-east-1
| stats count by StackStatusOne resource by identifier:
| awsget kind=AWS::SQS::Queue identifier="https://sqs.us-east-1.amazonaws.com/123456789012/payments-events" region=us-east-1A type the app has no alias for - works because Cloud Control can list it:
| awsget kind=AWS::ECR::Repository region=us-east-1Inventory across every account:
| awsget kind=instances account=* region=*
| spath path=State.Name output=state
| stats count by account region state| awslogs - CloudWatch Logs
Use awslogs to read CloudWatch logs from any service - Lambda, API Gateway, ECS and Fargate, RDS, VPC Flow Logs, or your own applications. With query= it runs a Logs Insights query; without it, it tails raw events matched by filter=, newest first.
| awslogs groups=<group|prefix*|"a,b">
[query=<insights query>] | [filter=<pattern>]
[start=<time>] [end=<time>] [limit=<int>]
[account=<name|*>] [region=<id|*>] [concurrency=<int>] [cache=<duration>]| Argument | Description |
|---|---|
groups= | Required. One or more log groups, comma-separated (quote the value when listing several). A trailing * is a name-prefix glob - /aws/lambda/payments-* - expanding to at most 200 groups for a raw tail, and at most 50 for a Logs Insights query, which is CloudWatch’s own cap per query. |
query= | A Logs Insights query. Billed per GB scanned. |
filter= | A CloudWatch filter pattern for the raw tail. * or empty matches every event. |
start=, end= | The window. Default: recent events. |
limit= | For the raw tail, the total events returned, shared fairly across the selected groups (never below one per group). A group that fills its share is named in a notice row, so a busy group cannot silently crowd the others out. |
Key fields: _time, logGroup, logStream, eventId, and _raw (the message). Logs Insights rows carry the query’s own columns.
Errors from a function in the last hour:
| awslogs groups=/aws/lambda/payments-api filter="ERROR" start=-1h region=us-east-1Lambda billed-duration trend from REPORT lines:
| awslogs groups=/aws/lambda/payments-api start=-3h region=us-east-1
query="filter @type = 'REPORT' | stats avg(@billedDuration) by bin(5m)"Every function in one prefix:
| awslogs groups=/aws/lambda/payments-* filter="Task timed out" start=-24h region=us-east-1
| where isnull(notice)
| stats count by logGroupThese are counts of the newest events limit= allows each group, not of the whole window. When a group holds more than its share, the command adds a row with a notice field saying so; where isnull(notice) keeps that row out of the count. For a count over the whole window, use a Logs Insights query= instead.
| awsmetrics - CloudWatch metrics
awsmetrics returns a metric time series via GetMetricData - one row per data point - or, with list=true, the metrics CloudWatch has via ListMetrics, which is what fills the Metrics Explorer’s pickers.
| awsmetrics namespace=<ns> metric=<name> [dimensions=<Name=Value,...>]
[stat=<Average|Sum|Minimum|Maximum|SampleCount|p99>] [period=<seconds>]
[expression=<expression>] [start=<time>] [end=<time>]
[account=<name|*>] [region=<id|*>] [concurrency=<int>] [cache=<duration>]
| awsmetrics list=true [namespace=<ns>] [metric=<name>] [dimensions=<Name[=Value]>] [recent=<bool>]| Argument | Description |
|---|---|
namespace=, metric= | The metric to read, e.g. AWS/Lambda and Throttles. |
dimensions= | Comma list of Name=Value. Quote it when it has more than one pair. |
stat= | The statistic. Default Average. |
period= | Datapoint period in seconds. |
expression= | A CloudWatch expression instead of a single metric. The request carries this one expression and nothing else, so it has to stand on its own: a Metrics Insights query (SELECT ... FROM SCHEMA(...)) or a SEARCH() expression. Math over other series, such as errors/invocations*100, has no series to refer to - compute a ratio in SPL from two searches instead. |
list=true | Listing mode: one row per metric with namespace, metric, dimensions (in the exact form dimensions= accepts back), and dimension_names. namespace=, metric=, and dimensions= become optional filters; a bare dimension name matches any value. recent=true keeps only metrics active in the last three hours (off by default, because S3 storage metrics publish once a day). A listing past 40 pages stops with a notice row. |
Key fields of a time series: _time, value, label (CloudWatch’s name for the series - the metric name, or the group of a Metrics Insights GROUP BY), and id. The rows do not repeat the namespace, metric, or dimensions you asked for; add them with eval when you combine searches. A listing returns namespace, metric, dimensions, and dimension_names instead.
Lambda throttles over the last three hours:
| awsmetrics namespace=AWS/Lambda metric=Throttles dimensions=FunctionName=payments-api stat=Sum period=300 start=-3h region=us-east-1Throttles for every function at once - a Metrics Insights query, with the inner quotes escaped:
| awsmetrics expression="SELECT SUM(Throttles) FROM SCHEMA(\"AWS/Lambda\", FunctionName) GROUP BY FunctionName" period=300 start=-3h region=us-east-1
| stats sum(value) as throttles by label
| where throttles>0S3 bucket size - two dimensions, so the value is quoted:
| awsmetrics namespace=AWS/S3 metric=BucketSizeBytes dimensions="BucketName=payments-archive,StorageType=StandardStorage" stat=Average period=86400 start=-7d region=us-east-1Which functions publish Invocations - the dimension tuples a picker offers:
| awsmetrics list=true namespace=AWS/Lambda metric=Invocations region=us-east-1| awscloudtrail - management events
awscloudtrail looks up recent CloudTrail management events with LookupEvents - who did what, when, from where. CloudTrail keeps 90 days of management events for this API.
| awscloudtrail [attribute=<name>] [value=<value>] [start=<time>] [end=<time>] [limit=<int>]
[account=<name|*>] [region=<id|*>] [concurrency=<int>] [cache=<duration>]| Argument | Description |
|---|---|
attribute= | One of EventName, EventSource, Username, ResourceName, ResourceType, EventId, AccessKeyId, ReadOnly. |
value= | The value to match for that attribute. |
start=, end= | The window; start=-24h for the last day. |
limit= | Cap the events returned per account and region. |
Key fields: _time, event_name, event_source, username, event_id, access_key_id, read_only, and _raw with the full event JSON - spath it for the rest (sourceIPAddress, userAgent, requestParameters). Global services such as IAM record their events in us-east-1. STS is regional unless the caller used its global endpoint: a call to sts.<region>.amazonaws.com is recorded in that region, and this app’s own AssumeRole calls are made that way.
Who launched instances in the last day:
| awscloudtrail attribute=EventName value=RunInstances start=-24h region=us-east-1
| spath path=sourceIPAddress output=source_ip
| spath path=userAgent output=user_agent
| table _time username source_ip user_agentEverything one user did this week:
| awscloudtrail attribute=Username value=alice start=-7d region=us-east-1
| stats count by event_source event_name| awscost - Cost Explorer
awscost returns cost and usage from Cost Explorer. Every request is billed by AWS (about $0.01), so the command runs once per account whatever region= says, its results are cached for an hour, and the Cost dashboards wait for a Submit.
| awscost [start=<time>] [end=<time>] [granularity=<DAILY|MONTHLY|HOURLY>]
[metrics=<UnblendedCost,...>] [group_by=<DIMENSION|TAG:key>]
[account=<name|*>] [concurrency=<int>] [cache=<duration>]| Argument | Description |
|---|---|
start=, end= | The window: a date, epoch seconds, or relative time. Without them, the search’s time-range picker; without that, the last 30 days. Bounds widen to whole UTC days, Cost Explorer’s granularity. |
granularity= | MONTHLY (default), DAILY, or HOURLY where enabled. |
metrics= | Comma list such as "UnblendedCost,UsageQuantity" - quote it. Default UnblendedCost. |
group_by= | A dimension (SERVICE, REGION, LINKED_ACCOUNT, USAGE_TYPE) or TAG:<key>. |
Key fields: _time and start (the period start), end, account, group (the dimension or tag value), and one field per metric with its amount (UnblendedCost) and its unit (UnblendedCost_unit).
Daily cost by service for a month:
| awscost granularity=DAILY group_by=SERVICE start=2026-08-01 end=2026-09-01 account=prod
| timechart span=1d sum(UnblendedCost) by groupMonth over month by team tag:
| awscost granularity=MONTHLY group_by=TAG:team start=-2mon@mon account=*| awsathena - Athena queries
awsathena starts an Athena query, waits for it (cancelling your search cancels the query), and streams the result rows keyed by column name. AWS bills per TB scanned.
| awsathena query=<sql> [database=<name>] [output_location=<s3://...>]
[account=<name|*>] [region=<id|*>] [concurrency=<int>] [cache=<duration>]| Argument | Description |
|---|---|
query= | Required. The SQL to run. Quote it. |
database= | The Glue database the query runs against. |
output_location= | The S3 location for results, when the Athena workgroup does not set one. |
Top CloudTrail event names from an Athena table:
| awsathena database=cloudtrail_logs query="SELECT eventname, count(*) AS c FROM cloudtrail GROUP BY 1 ORDER BY c DESC LIMIT 20" region=us-east-1| awsglue - the Glue Data Catalog
awsglue browses the Data Catalog that Athena queries: databases, tables, and partitions.
| awsglue resource=<databases|tables|partitions> [database=<name>] [table=<name>]
[expression=<partition filter>] [catalog_id=<id>]
[account=<name|*>] [region=<id|*>] [concurrency=<int>] [cache=<duration>]tables requires database=; partitions requires database= and table=. Key fields depend on the resource: a database row has database, description, location_uri, and catalog_id; a table row has table, database, table_type, owner, and description; a partition row has database, table, and the partition values. Every row carries _raw with the catalog object’s full JSON, which is where a table’s storage location lives:
| awsglue resource=tables database=cloudtrail_logs region=us-east-1
| spath path=StorageDescriptor.Location output=location
| table table table_type location| awstag - resources by tag
awstag finds resources by tag through the Resource Groups Tagging API. Each row carries the resource’s arn, and each tag is flattened into a tag_<key> field. That API knows a resource only if it carries a tag now or did once: a resource that was never tagged is not in its answer at all, so awstag is the right tool for “what carries this tag” and the wrong one for “what has no tags”. For that, list the kind with | awsget and read its Tags.
| awstag [tag=<Key=Value,...>] [resource_type=<service:type>]
[account=<name|*>] [region=<id|*>] [concurrency=<int>] [cache=<duration>]| Argument | Description |
|---|---|
tag= | Comma list of Key=Value filters. Quote it when it has more than one pair: tag="env=prod,team=payments". |
resource_type= | Narrow by ARN service type, e.g. ec2:instance. |
| awstag tag=env=prod region=us-east-1
| rex field=arn "arn:aws:(?<service>[^:]+):"
| stats count by service| awsjson - format JSON for reading
| awsget, | awscloudtrail, and | awsglue return the whole JSON document of each row in _raw. Pipe through awsjson to read it as YAML, or as indented JSON with format=json. The other commands have nothing for it by default: | awslogs puts the log message in _raw, which is JSON only when the application logged JSON, and | awsmetrics, | awscost, | awstag, and | awsathena return fields and no _raw. Point field= at any field that holds JSON. This is a streaming command - it transforms rows, it fetches nothing.
... | awsjson [field=<field>] [output=<field>] [format=<yaml|json>]| Argument | Description |
|---|---|
field= | Input field holding the JSON (default _raw). |
output= | Field to write the result to (default: rewrite the input field in place). |
format= | yaml (default) or json. |
Rows whose field is empty or is not JSON pass through untouched.
| awsget kind=roles account=prod
| awsjson field=AssumeRolePolicyDocument output=trust format=json
| table RoleName trustRecipes
Instances not running, with their type and launch time:
| awsget kind=instances account=* region=*
| spath path=State.Name output=state
| where state!="running"
| table account region InstanceId InstanceType state LaunchTimeUnattached EBS volumes (two listings joined on the association kind; volumes list by identifier only, so detail=true brings the size and type):
| awsget kind=volumes detail=true region=us-east-1
| join type=left identifier
[ | awsget kind=volume-attachments region=us-east-1
| rex field=identifier "^(?<identifier>vol-[^|]+)\|(?<instance>i-.+)$"
| table identifier instance ]
| where isnull(instance)
| table identifier Size VolumeTypeCorrelate a CloudTrail change with the resource as it is now:
| awscloudtrail attribute=EventName value=ModifySecurityGroupRules start=-24h region=us-east-1
| table _time username _raw| awsget kind=security-groups identifier=sg-0a1b2c3d detail=true region=us-east-1
| awsjsonHistory from CloudTrail, current state from Cloud Control - in the same session, without leaving Splunk for the console.