aws-waste-hunter
Read-only, auditable AWS waste scanner that tells you how many dollars you can save. Built by Helyx IT.
Status: alpha (0.1.0). Parallel multi-region and cross-account scans, live pricing, six checks including metric-based idle detection with a hard cost cap.
Why this one
- It can't change your account. Every AWS call is
Describe*,List*orGet*, enforced three ways: in code, in tests, and in the IAM policy you attach. - It runs on your machine. No SaaS, no agent, no telemetry. Nothing leaves your account.
- You can read all of it. Small codebase, minimal dependencies, published least-privilege IAM policy.
- It speaks dollars. Every finding has a monthly cost and a savings estimate, priced from the live AWS Price List API.
Install
pipx install aws-waste-hunter # after the first PyPI release
docker build -t aws-waste-hunter . && docker run --rm -v ~/.aws:/home/scanner/.aws:ro \
aws-waste-hunter scan --region us-east-1 --profile my-sso-profile
pip install --require-hashes --no-deps -r requirements.lock && pip install --no-deps . # from source, hash-pinned
See a sample report (fictional data).
Usage
pip install -e .
aws-waste-hunter scan --region us-east-1 --profile my-sso-profile
aws-waste-hunter scan --regions us-east-1,eu-west-1 --format json --output report.json
aws-waste-hunter scan --all-regions
aws-waste-hunter scan --region us-east-1 --pricing offline # no Price List calls
aws-waste-hunter scan --region us-east-1 --max-metrics 50 # tighter CloudWatch cost cap
aws-waste-hunter scan --all-regions --concurrency 12 # parallel (default 8, max 16)
# Other accounts: assume a read-only role in each (repeat --role-arn for more accounts)
aws-waste-hunter scan --all-regions \
--role-arn arn:aws:iam::222222222222:role/aws-waste-hunter-scanner \
--external-id "$WASTE_HUNTER_EXTERNAL_ID"
Create the cross-account role with the Terraform module in
terraform/scanner-role: trust is limited to the principals you list
and requires an ExternalId; permissions are exactly iam/policy.json.
Attach iam/policy.json to the role you scan with. Reports are written
with 0600 permissions because they describe your account.
Checks
| ID | Finds |
|---|---|
ebs-unattached |
EBS volumes not attached to anything |
ebs-gp2-to-gp3 |
in-use gp2 volumes that could be gp3 (~20% cheaper) |
eip-unassociated |
Elastic IPs allocated but not associated |
logs-no-retention |
CloudWatch log groups that never expire |
nat-idle |
NAT gateways (older than 7 days) that moved 0 bytes in the last 7 days |
lb-idle |
Application/Network load balancers (older than 7 days) with no traffic in 7 days |
nat-idle and lb-idle read CloudWatch (GetMetricData, billed ~$0.01 per 1,000 metrics).
Every query is charged against a budget first: --max-metrics (default 200 per account and
region, about $0.002). If the cap is reached the check stops, keeps what it found, and reports
the error. Their dollar figures use us-east-1 list prices, so treat them as estimates.
A check that fails (for example a missing permission) is listed in the report and the exit code is 1. It is never silently skipped.
Pricing
Prices come from the AWS Price List API per region, are cached for 24 hours, and fall back to an offline us-east-1 list-price table if the lookup fails. Every report states which source was used. Live and cached values must be positive and within a sane band of the reference, so a bad parse or a tampered cache cannot inflate your numbers. Amounts are estimates, not quotes.
Security model
- Read-only guard on every call, plus a CI test that fails on any other operation.
- Least-privilege IAM policy with no wildcards; every check's required actions are test-verified against it.
- AWS clients can only be created through one guarded helper (bounded timeouts, bounded retries, validated region); a test fails if any other code creates a raw client.
- Region names are validated before they reach endpoints or file paths.
- Resource names and tags are treated as untrusted input when rendering reports.
- Cross-account scans use short-lived (1h) assumed-role credentials that stay in memory; the
only non-read operation allowed through the guard is the exact
sts:AssumeRole. - Standard AWS credential chain / SSO only. Credentials are never stored, logged or sent.
- GitHub Actions are pinned to commit SHAs.
See SECURITY.md to report a vulnerability.
Pro (planned)
The open-source scanner finds the mechanical waste. Pro is where it becomes a savings program. These features are on the roadmap and are not available yet; the order below is the rough build order.
Find more, across everything
- Org-wide scans. Cross-account scanning works today with
--role-arn; Pro adds automatic discovery of every account in your AWS Organization. - More metric-based idle detection. Idle EC2 and RDS (NAT gateways and load balancers are already in the open-source scanner). The waste that metadata alone can't show, with a hard cost cap so the scan itself never surprises you.
- EKS right-sizing. Requests vs real usage from Datadog or Prometheus, plus the autoscaler blockers that keep nodes alive. The same playbook behind a 70%+ node reduction.
- Commitment review. Savings Plans and Reserved Instance coverage, usually the single biggest lever.
Fix it safely
- Fix-as-code merge requests. Generates the Terraform or CLI change as a GitLab or GitHub MR for a human to review. It never applies anything itself.
- Terraform cost guard. Estimates the monthly cost of every
terraform planand flags expensive patterns before they merge. - Suppressions with expiry. Accept a finding per resource or tag, with an owner and a review date, kept as policy-as-code in your repo.
Prove the savings
- Trend history and scheduled scans. Weekly digests to Slack or email and a running total of dollars saved, so the program has numbers behind it.
- AI prioritization in your own account. Ranks findings by effort versus payoff using Bedrock (or a local model). The AI only summarizes: it never detects and never acts, and nothing leaves your account.
- Export anywhere. SARIF, CSV and Jira.
Don't want to run it yourself?
Helyx does manual, expert-led AWS reviews with a guaranteed 15% savings, and goes where automation can't: architecture, data-transfer design and commitment strategy. Book a call.
Develop
python3.13 -m venv ~/.venvs/aws-waste-hunter && source ~/.venvs/aws-waste-hunter/bin/activate
pip install -e ".[dev]"
ruff check . && mypy src && pytest
Tests use moto and canned Price List responses; no AWS account or credentials needed.
License
Apache-2.0
Metadata
Release files for aws-waste-hunter 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| aws_waste_hunter-0.1.0.tar.gz | 38.5 kB | With provenance | Details for aws_waste_hunter-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| aws_waste_hunter-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for aws_waste_hunter-0.1.0-py3-none-any.whl |
Total release size: 68.9 kB
Release files / aws_waste_hunter-0.1.0.tar.gz
| Download URL | aws_waste_hunter-0.1.0.tar.gz |
|---|---|
| Size | 38.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9d70a64f6b07ee878fca3b2d2860b96cf38c3197dbc613b70d49237f5e06d868
|
|
BLAKE2b-256 checksum How to use checksums |
2de45769de34581b8e4e36656b3df137810a70ea89825ddcede60b975375e8bd
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 6, 2026.
Transparency logRelease files / aws_waste_hunter-0.1.0-py3-none-any.whl
| Download URL | aws_waste_hunter-0.1.0-py3-none-any.whl |
|---|---|
| Size | 30.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4a0b81b054f3a3249c843c9975dfba9d9e01927cdae46b844a1c5b1d5ebf41cc
|
|
BLAKE2b-256 checksum How to use checksums |
b78c5f6e76e63a86f51d6c067e3e0fd68e7cf11be33ba09a24aad83a3d431648
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 6, 2026.
Transparency logSecurity for aws-waste-hunter 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for aws_waste_hunter-0.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 6, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.