Tracing unowned cloud infrastructure with federated search across Amazon S3 and Snowflake
This article is one of three investigation examples in a series. See Investigating security incidents across Amazon S3 and Snowflake with federated search for the reference architecture, dataset list, and prerequisites used in this example.
Cloud spend appears in eu-west-1, a region with no production footprint. No alert was fired and no change record explains the activity. This investigation starts from the provisioning record rather than from a detection.
How federated search in Splunk Cloud Platform helps with this use case
Step 1: Where is compute being created?
Use Amazon S3 as the source.
FROM s3_cloudtrail WHERE eventName="RunInstances" AND earliest=-90d | stats count() AS launches BY userIdentity, awsRegion | sort -launches
Three service identities launch steadily in us-east-1 and us-west-2. One row shows svc-automation launching nine instances in eu-west-1, a region where that identity has never provisioned compute before.

The region alone isn't the signal; people might work in eu-west-1 routinely. The signal is a new provisioning pattern for a specific identity.
You should preserve the instance IDs, launch times, AMIs, security groups, tags, and role attachments. Continue by checking whether the provisioning was authorized and what the instances are doing.
Step 2: Was there a change record?
Use an index in Splunk Cloud Platform as the source.
index=linux_secure sourcetype=linux_secure | where like(_raw, "%terraform%") OR like(_raw, "%ansible-playbook%") | timechart span=1d count() AS change_runs
Sanctioned provisioning runs through the CI runner and appears on six of seven days. The day the nine instances launched is empty.

You should treat the provisioning as unauthorized until the service owner or change-management system confirms otherwise. Search CI, deployment, and ticketing sources for a late-arriving record before closing the investigation.
Step 3: What are they doing?
Use Amazon S3 as the source.
FROM s3_vpc_flowlogs WHERE dstaddr="192.0.2.200" AND earliest=-90d | stats count() AS flows, dc(srcaddr) AS hosts, sum(bytes) AS total BY dstport | eval mb=round(total/1024/1024, 1)
There are 126 flows from nine hosts to one external address on port 3333, the stratum mining-pool protocol, carrying approximately 420 MB. The few destinations, long-lived connections, and steady volume are consistent with cryptomining activity.

You should isolate or terminate the unauthorized instances according to your incident-response policy, preserve relevant disk and cloud evidence, block the mining-pool destination, and rotate any credentials available to the workload.
Step 4: Who owns these identities?
Use Amazon S3 and Snowflake as the sources.
FROM s3_cloudtrail WHERE earliest=-90d
| stats count() AS calls, dc(eventName) AS apis, dc(awsRegion) AS regions BY userIdentity
| join type=left left=L right=R where L.userIdentity=R.OS_ACCOUNT
[FROM sf_employee_status | fields OS_ACCOUNT, FULL_NAME, DEPARTMENT, EMPLOYMENT_STATUS]
| eval identity='L.userIdentity', calls='L.calls', apis='L.apis', regions='L.regions',
owner=coalesce('R.FULL_NAME', "— none —"), dept=coalesce('R.DEPARTMENT', "— none —")
| fields identity, owner, dept, calls, apis, regions
| sort owner, -calls
Fifteen identities appear. Twelve resolve to named employees with departments. Three (svc-automation, svc-backup, and svc-etl) have no HR record. The identity that provisioned nine mining instances in a new region has no owner and no obvious person to contact.

In this case, the absence of a Snowflake record is the finding. Federated search makes it possible to enumerate unowned identities across the cloud estate while investigating the immediate incident.
You should assign accountable owners, suspend or rotate unowned service credentials, review service-account lifecycle controls, and add a recurring control that identifies cloud identities with no matching owner record.

