Resource creators (CloudTrail)
Point StaleSweep at the S3 bucket your CloudTrail trail delivers to, and every flagged resource shows who created it — used as its owner wherever no ownership tag says otherwise.
Most accounts tag only some of what they run, and the first question anyone asks of a flagged resource is whose it is. CloudTrail recorded the call that created it, with the identity that made it. StaleSweep reads those records from your trail’s bucket with the same read-only role it already uses — nothing is created in your account, and nothing in the bucket is changed.
- Only the days that matter. Each flagged resource records when it was created. The lookup opens only the log folders for the days around that moment (two, or three across midnight), in the resource's region, and reads each log file at most once — never the whole bucket.
- Only who made the call. From the matching create event it keeps the identity: its type, ARN and name, an assumed role's session name, the AWS service that called on your behalf, and the STS source identity, with the event's name and time. No request parameters, IP addresses or user agents are stored.
- Tags still win. A resource's owner is its ownership tag when it has one, and the CloudTrail creator otherwise. Both appear in the Owner section on the Resources page and in the owner and creator fields of AI access (MCP) results.
- As far back as your trail keeps. It reads the bucket rather than CloudTrail's event history API, which only covers 90 days. Most waste is older than that; the bucket holds whatever your trail's retention keeps.
Before you start
- A trail that delivers management events to S3 — ideally a multi-region trail, or an organization trail for an AWS Organization.
- The trail’s bucket and prefix: in the AWS console, open CloudTrail → Trails and pick the trail; its storage location shows both. The prefix is the folder that holds
AWSLogs/, if the trail was given one. - If the trail encrypts its logs with a KMS key (SSE-KMS), that key’s ARN — the
…:key/…form, not an alias.
Set it up while connecting an account
- In the connect wizard, on the Create the IAM role step, turn on Show who created each resource.
- Enter the bucket (pasting
s3://bucket/prefixfills both fields), the prefix if any, and the KMS key ARN if the trail uses one. The template and the deploy link update to setCloudTrailBucketandCloudTrailKmsKeyArnfor you — deploy only once the wizard says they do. - Deploy the stack and paste the role ARN, as usual.
- Once the connection is made, StaleSweep turns the lookup on with that bucket. If AWS refuses the read, the last step says why — the connection itself is fine — and offers the guided setup with your bucket already filled in.
Add it to an existing connection
1. Let the role read the bucket
In CloudFormation, update your StaleSweep stack and set the CloudTrailBucket parameter (and CloudTrailKmsKeyArn for a KMS-encrypted trail). If the stack predates these parameters, choose Replace existing template with the current template:
https://stalesweep-cloudformation.s3.us-west-2.amazonaws.com/cloudformation/stalesweep-scan-role.yamlFor an AWS Organization, update the stack in the management account.
2. Point the lookup at the bucket
- On the Providers page, open the connection’s Edit dialog and choose Set up CloudTrail.
- Find my trail fills in the bucket and prefix from the trails your account reports; or enter them yourself.
- Test connectionruns the same check saving does — the role can read the bucket, and it holds this account’s logs — without saving anything.
- Save and start reading. The Edit dialog then shows when the lookup last ran and how many resources it has answered.
AWS Organizations
An organization trail delivers every account’s events to one bucket, under AWSLogs/<organization-id>/<account-id>/. Set the lookup up on the management account’s connection and it answers for every member account too, reading each member from its own folder with the management account’s role — members need no stack change and no setup of their own. A member’s Edit dialog shows Via organization with the last run. A member the bucket has no folder for is named on the status line; one whose logs live elsewhere can have a lookup of its own, which then takes over for it.
A bucket in another account
Organization trails usually deliver to a Log Archive account’s bucket. The stack can grant only what your own account controls, so that bucket’s policy must also allow StaleSweep’s role. The wizard shows the exact role ARN to use. Add these statements to the bucket policy, keeping the ones CloudTrail needs:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "StaleSweepListTrailLogs",
"Effect": "Allow",
"Principal": { "AWS": "<StaleSweep role ARN shown in the wizard>" },
"Action": ["s3:ListBucket", "s3:GetBucketLocation"],
"Resource": "arn:aws:s3:::<trail-bucket>"
},
{
"Sid": "StaleSweepReadTrailLogs",
"Effect": "Allow",
"Principal": { "AWS": "<StaleSweep role ARN shown in the wizard>" },
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::<trail-bucket>/<prefix/>AWSLogs/*/CloudTrail/*"
}
]
}If the trail encrypts with a KMS key in that account, add this statement to the key policy too:
{
"Sid": "StaleSweepDecryptTrailLogs",
"Effect": "Allow",
"Principal": { "AWS": "<StaleSweep role ARN shown in the wizard>" },
"Action": "kms:Decrypt",
"Resource": "*",
"Condition": { "StringLike": { "kms:ViaService": "s3.*.amazonaws.com" } }
}arn:aws-us-gov:, arn:aws-cn:). Use the role ARN exactly as the wizard shows it.What the role is granted
Setting CloudTrailBucketadds one managed policy to the scan role. It may list and read anything under the bucket’s AWSLogs/ folders (at the root or under a prefix), and decrypts only through S3. Left blank, it grants nothing.
StaleSweepCloudTrailReadPolicy: # only when CloudTrailBucket is set
Statement:
- Effect: Allow # list the AWSLogs/ folders only
Action: [s3:ListBucket, s3:GetBucketLocation]
Resource: arn:aws:s3:::<CloudTrailBucket>
Condition:
StringLikeIfExists:
s3:prefix: ['AWSLogs/*', '*/AWSLogs/*']
- Effect: Allow # read objects under AWSLogs/ only
Action: s3:GetObject
Resource:
- arn:aws:s3:::<CloudTrailBucket>/AWSLogs/*
- arn:aws:s3:::<CloudTrailBucket>/*/AWSLogs/*
- Effect: Allow # only when CloudTrailKmsKeyArn is set
Action: kms:Decrypt
Resource: <CloudTrailKmsKeyArn>
Condition:
StringLike:
kms:ViaService: ['s3.*.amazonaws.com', 's3.*.amazonaws.com.cn']AWSLogs/ is where every AWS service delivers logs, not only CloudTrail. If load balancer access logs, VPC flow logs or AWS Config snapshots go to the same bucket, the role can read those too, although the lookup only ever opens files under …/CloudTrail/. To keep the access to CloudTrail alone, deliver the trail to a bucket of its own. For a bucket in another account, the bucket policy above already limits reads to the CloudTrail/ folders.What you’ll see
The lookup runs in the background about once an hour, each run within a fixed budget of files, bytes and time; a large backlog takes several runs. Each resource ends in one of these states:
| Status | What it means |
|---|---|
| Found | The create call was in the logs. Its creator is shown, and used as the owner when the resource has no ownership tag. |
| Not found | Every log file for the creation days was read and none created this resource. Common for resources created as a side effect of another call — an EBS volume launched with an instance, or a snapshot made by CreateImage — which have no create event of their own. |
| No logs | The trail held no log files at all for the days the resource was created: its retention had already expired them, the trail was created later, or it does not log that region. This says nothing about who created it. |
| Can't be looked up | AWS reported no creation date for the resource, so there is no day to open; or its kind has no create event a trail records (incomplete multipart uploads are an S3 data event). |
| Pending | Not judged yet. Resources created in the last two days wait for CloudTrail to finish delivering their logs, and a large backlog is worked through over several runs. |
The S3 requests are made in your account: a listing and a handful of reads for each day folder opened. For most accounts that is a few cents a month.
Troubleshooting
| What you see | What to do |
|---|---|
| “StaleSweep’s role isn’t allowed to read this bucket yet” | The stack has no CloudTrailBucket set, or names another bucket — update it (see above). A bucket in another account also needs its bucket policy; a trail encrypted with KMS needs CloudTrailKmsKeyArn and, across accounts, the key policy. |
| “Readable, but no logs for this account” | The prefix doesn’t match the trail’s storage location. Use the folder that holds AWSLogs/. For an organization trail, set it up on the management account’s connection, with the organization trail’s own bucket. |
| A member account named on the status line | The organization trail’s bucket holds no folder for that account: the trail doesn’t cover it, or its logs go elsewhere. Its resources stay pending; give that member its own lookup if its logs live in another bucket. |
| “Took too long” or “more folders than a trail writes” | Point the prefix at the trail’s own folder (the one holding AWSLogs/), not the bucket root of a bucket shared with other logs. |
| Many resources show No logs | Your trail’s retention is shorter than the age of your oldest waste, or the trail doesn’t log every region. Longer retention covers resources created from then on. |
Turning it off
Edit connection → Turn off stops the lookup at once; the bucket is kept for next time. To withdraw the read itself, clear CloudTrailBucket on the stack. See Security & privacy for how the read fits StaleSweep’s access model.