cor

command module
v0.0.0-...-e874bde Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 30, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

README

COR


COR (Cloud Orphan Resources) is a CLI tool to find (and optionally delete) potentially orphaned AWS resources.

What it does

COR currently supports:

  • EBS volumes: unattached volumes (volumes)
  • EBS snapshots: snapshots not referenced by AMIs/volumes and not created by lifecycle policy (snapshots)
  • AMIs: images not used by instances or launch templates (images)
  • Elastic IPs: unassociated EIPs (elasticips)
  • ENIs: unattached network interfaces (enis)
  • ELBv1: classic ELBs with unhealthy instances (elbv1)
  • ELBv2: application/network LBs with target groups that have no valid targets (elbv2)
  • ELBv2 target groups: target groups not attached to any LB (targetgroups)
  • Auto Scaling Groups: “empty” ASGs (no instances, min/desired=0, no LB/TG) (autoscaling)
  • NAT gateways: list and optionally delete (natgateways)
  • RDS: stopped instances + manual snapshots (rds)
  • CloudWatch Logs: log groups (optionally delete) (logs)
  • EFS: file systems with zero mount targets (efs)
  • ECR: untagged/old container images (ecr)
  • Route53: hosted zones with only NS/SOA records (route53zones)
  • VPC Endpoints: interface endpoints with no ENIs (vpcendpoints)
  • Client VPN: endpoints with zero active connections (clientvpn)
  • Site-to-Site VPN: connections with no tunnels up (vpnconnections)
  • Transit Gateway: VPC attachments without route table association (tgwattachments)
  • Lambda Functions: functions not invoked in 90+ days, old versions, unused provisioned concurrency (lambda)
  • ElastiCache: clusters with zero connections for 24+ hours (elasticache)
  • OpenSearch: domains with no indexing/search activity (opensearch)
  • DynamoDB Tables: tables with zero read/write activity, empty tables (dynamodb)
  • S3 Buckets: empty buckets, incomplete multipart uploads (s3buckets)
  • ECS Clusters: clusters with no services or running tasks (ecs)

Cost Impact

COR helps identify resources that continue to incur AWS charges even when orphaned or unused:

  • EBS Volumes: ~$0.08-0.10/GB-month (gp3), ~$0.10/GB-month (gp2)
  • EBS Snapshots: ~$0.05/GB-month
  • AMIs: Includes underlying snapshot costs
  • Elastic IPs: $0.005/hour when unassociated (~$3.60/month)
  • NAT Gateways: $0.045/hour + data transfer ($32/month minimum)
  • ALB/NLB: $0.0225/hour ($16/month per load balancer)
  • Classic ELB: $0.025/hour ($18/month)
  • RDS Instances: Varies by instance type (even when stopped, snapshots incur costs)
  • RDS Snapshots: ~$0.095/GB-month
  • CloudWatch Logs: $0.50/GB ingestion + $0.03/GB-month storage
  • EFS: $0.30/GB-month (Standard), $0.016/GB-month (Infrequent Access)
  • ECR: $0.10/GB-month for storage
  • Route53 Hosted Zones: $0.50/month per zone
  • VPC Endpoints: $0.01/hour per AZ ($7/month)
  • Client VPN: $0.10/hour ($72/month)
  • Site-to-Site VPN: $0.05/hour per connection ($36/month)
  • Lambda Functions: Provisioned concurrency $100-500/month per function; storage for old versions
  • ElastiCache: cache.m5.large ~$105/month, cache.r6g.xlarge ~$217/month
  • OpenSearch: t3.small.search ~$26/month, r6g.large.search ~$101/month + $0.135/GB-month storage
  • DynamoDB Tables: Provisioned mode $0.00065/hour per WCU, $0.00013/hour per RCU; storage $0.25/GB-month
  • S3 Buckets: Storage $0.023/GB-month (Standard); request costs; incomplete uploads consume storage
  • ECS Clusters: Free, but prevents cleanup of NAT Gateway, ALB, and related infrastructure

Note: Prices are approximate and vary by region. Check current AWS pricing for your region.

Install

From the repo:

make build          # produces ./cor
./cor --help

make build injects version/commit/buildDate from git via -ldflags. Plain go build -o cor . also works.

Run make help for the full target list (test, lint, cover, dist, …).

Authentication

Global flag: --auth-method (default: AWS_CREDENTIALS_FILE)

  • AWS_CREDENTIALS_FILE: uses your standard AWS shared config/credentials files with --profile
  • ENV_SECRET: uses AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY

Configuration (file + env)

COR reads config from:

  • --config /path/to/file.yaml, or
  • $HOME/.cor.yaml

It also supports env vars prefixed with COR_ (hyphens become underscores).

Precedence: CLI flags > config file > env vars > defaults

Example env vars:

  • COR_REGION=us-east-1
  • COR_PROFILE=prod
  • COR_AUTH_METHOD=AWS_CREDENTIALS_FILE
  • COR_DELETE=true
  • COR_YES=true
  • COR_ON_ERROR=continue
  • COR_DRY_RUN=true
  • COR_FORMAT=json
  • COR_LOG_FORMAT=json
  • COR_METRICS_FILE=/var/log/cor.ndjson
  • COR_STATE_FILE=/var/lib/cor/state
  • COR_SORT_BY=Name
  • COR_SORT_DESC=true

Common flags

  • --region, -r: AWS region (default: us-east-1)
  • --profile, -p: shared config profile (default: default)
  • --auth-method, -a: AWS_CREDENTIALS_FILE or ENV_SECRET
  • --delete: actually delete/release resources (prompts for confirmation)
  • --yes: skip the delete confirmation prompt — use only in automation
  • --dry-run: print what would be deleted without calling AWS delete APIs
  • --on-error stop|continue: per-item delete-error policy (default stop)
  • --state-file <path>: persist deleted-resource keys; skip them on re-run
  • --sort-by: sort output by a column name (buffers results; disables streaming)
  • --sort-desc: descending sort
  • --format table|json|csv: output format (default table)
  • --log-format text|json: log line format (default text)
  • --metrics-file <path>: append a per-run JSON metrics summary to this path
  • --timeout: overall command timeout (e.g. 5m)
  • --config: config file path (default: $HOME/.cor.yaml)

Examples

List orphaned EBS volumes:

./cor volumes --region us-east-1 --profile default

Delete orphaned EBS volumes (will prompt):

./cor volumes --delete

Filter ELB by name pattern:

./cor elbv1 --filter-by-name "prod-*" --show-tags

Filter resources by tags:

./cor volumes --filter-by-tags "Environment=dev,Owner=team-a"
./cor elbv2 --filter-by-tags "CostCenter=engineering"

Sort output for easier analysis:

./cor snapshots --sort-by "Size" --sort-desc
./cor volumes --sort-by "CreateTime"

Use config file for consistent settings:

./cor --config ./prod-config.yaml volumes

Preview deletes without calling AWS (--dry-run):

./cor volumes --delete --dry-run

Non-interactive delete for automation (--yes):

./cor volumes --delete --yes --on-error continue

Machine-readable output (--format):

./cor volumes --format json
./cor snapshots --format csv --sort-by Size --sort-desc > orphans.csv

Resumable runs with a state file:

# first run records every deleted ID; interrupt at any time
./cor volumes --delete --yes --state-file /tmp/cor-volumes.state
# re-run skips already-deleted IDs
./cor volumes --delete --yes --state-file /tmp/cor-volumes.state

Per-run metrics + JSON logs (good for CI / cron):

./cor volumes --log-format json --metrics-file /var/log/cor-metrics.ndjson

List orphan AMIs, including those used by instances:

./cor images --include-used-by-instance

Check ECR for old/untagged images (30+ days):

./cor ecr --days-old 30

Find Route53 zones with only NS/SOA records:

./cor route53zones

List RDS instances and manual snapshots:

./cor rds

Find Lambda functions not invoked in 90+ days:

./cor lambda
./cor lambda --days-since-invocation 180  # Custom threshold

Find idle ElastiCache clusters:

./cor elasticache
./cor elasticache --hours-zero-connections 48  # Zero connections for 48+ hours

Find orphaned OpenSearch domains:

./cor opensearch
./cor opensearch --days-no-indexing 14 --hours-no-searches 48  # Custom thresholds

Find idle DynamoDB tables:

./cor dynamodb
./cor dynamodb --days-no-activity 60  # No activity for 60+ days

Find orphaned S3 buckets:

./cor s3buckets
./cor s3buckets --check-lifecycle  # Also check for missing lifecycle policies

Find empty ECS clusters:

./cor ecs

Troubleshooting

Permission Denied Errors

  • Ensure your IAM user/role has read permissions for the resource type you're checking
  • For delete operations, write/delete permissions are required
  • Common required permissions: ec2:Describe*, elasticloadbalancing:Describe*, rds:Describe*, etc.
  • Use AWS IAM Policy Simulator to verify permissions

Timeout Issues

  • Use the --timeout flag to increase execution time for large environments
  • Consider filtering by region or resource tags to reduce scope
  • Some commands (like snapshots, images) can take longer in accounts with many resources

No Resources Found

  • Verify you're using the correct region with --region or -r
  • Check that resource state filters match your use case (e.g., volumes must be in 'available' state)
  • Ensure your credentials have permission to view the resources
  • Try running with --profile to verify you're using the correct AWS account

Rate Limiting / Throttling

  • AWS APIs have rate limits; COR implements retries with exponential backoff
  • If you consistently hit limits, consider running during off-peak hours
  • Use filtering options to reduce the number of API calls

Memory Issues

  • COR uses streaming output by default to keep memory usage low
  • Avoid using --sort-by for very large result sets (requires buffering all results)
  • If issues persist, check for resource leaks or file an issue on GitHub

Development

The repo ships a Makefile covering the common workflows:

make build              # compile ./cor with ldflags-injected version
make test               # go test ./...
make test-race          # go test -race ./...
make cover              # write coverage.out + print the summary
make lint               # golangci-lint run ./...
make vet                # go vet ./...
make fmt                # gofmt -s -w .
make tidy               # go mod tidy
make vendor             # go mod vendor
make run ARGS='volumes --region us-east-1'
make dist               # cross-compile linux+darwin x amd64+arm64 into ./dist
make clean              # remove ./cor, coverage.out, dist/
make help               # list all targets

Architecture, command pattern, and contributor notes live in CLAUDE.md, CONTRIBUTING.md, and (for deeper backgrounder) research.md.

Profiling (optional)

This binary can expose pprof endpoints only when enabled:

  • COR_PPROF=1 enables the server
  • COR_PPROF_ADDR=:6060 sets the bind address (default :6060)

License

Apache-2.0 — see LICENSE and NOTICE.

Documentation

Overview

Copyright 2024 Cloud Orphaned Resources Contributors.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Directories

Path Synopsis
pkg
cost
Package cost provides estimated monthly USD pricing for AWS resources.
Package cost provides estimated monthly USD pricing for AWS resources.
handlers/aws/awstest
Package awstest provides small helpers for constructing fake AWS SDK clients driven by middleware.
Package awstest provides small helpers for constructing fake AWS SDK clients driven by middleware.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL