Skip to content

Backend Operations - AWS Inventory and Cleanup Toolkit

This guide walks through using a set of Bash scripts to inventory, analyze, and safely clean up AWS resources across all regions. These scripts help you identify legacy resources, reduce costs, and prepare for future infrastructure automation.


Prerequisites

Before using these scripts:

  1. Install and configure AWS CLI with SSO:
aws configure sso

Example profile:

[profile admin-cli-sso]
sso_session = james-mbp-cli
sso_account_id = <your-account-id>
sso_role_name = AdministratorAccess
region = us-east-1
  1. Login with SSO:
aws sso login --profile admin-cli-sso
  1. Install jq (for JSON parsing):
brew install jq     # macOS
sudo apt install jq # Ubuntu/Debian
  1. Make all scripts executable:
chmod +x *.sh

Script Groups

Scripts are grouped into three main categories:

  • Inventory: Gather data about resources.
  • Analysis / Reporting: Identify unused or orphaned items.
  • Cleanup / Deletion: Remove unwanted resources in a safe order.

Inventory Scripts

get-organizations-summary.sh

Summarizes your AWS Organization structure — accounts, roots, and OUs. Useful for understanding your organization’s layout.

./get-organizations-summary.sh --profile admin-cli-sso

get-all-tagged-resources.sh

Lists all AWS resources across all regions using the Resource Tagging API.

./get-all-tagged-resources.sh --profile admin-cli-sso

get-ec2-instances.sh

Lists all EC2 instances (running or stopped) in every region.

./get-ec2-instances.sh --profile admin-cli-sso

get-ec2-network-details.sh

Inventories all EC2 networking components: VPCs, Subnets, Route Tables, IGWs, Security Groups, and NACLs.

./get-ec2-network-details.sh --profile admin-cli-sso

get-vpc-inventory.sh

Collects all VPC-related information in one sweep per region.

./get-vpc-inventory.sh --profile admin-cli-sso

Useful for confirming regional VPC structures.


get-s3-buckets.sh

Lists all S3 buckets globally and their regions.

./get-s3-buckets.sh --profile admin-cli-sso

Output: s3-buckets.jsonl


get-rds-inventory.sh

Inventories all RDS databases and snapshots.

./get-rds-inventory.sh --profile admin-cli-sso

get-ebs-volumes-all.sh

Lists all EBS volumes and shows if they’re attached or orphaned.

./get-ebs-volumes-all.sh --profile admin-cli-sso

get-ebs-snapshots.sh

Lists all EBS snapshots owned by your account.

./get-ebs-snapshots.sh --profile admin-cli-sso

get-owned-amis.sh

Lists all AMIs you own (to catch legacy images).

./get-owned-amis.sh --profile admin-cli-sso

get-cloudformation-stacks.sh

Lists all CloudFormation stacks, even deleted or failed ones, across all regions.

./get-cloudformation-stacks.sh --profile admin-cli-sso

Useful for understanding what provisioned older resources.


get-elb-inventory.sh

Inventories Classic ELBs and ALB/NLB load balancers.

./get-elb-inventory.sh --profile admin-cli-sso

get-autoscaling.sh

Lists all Auto Scaling Groups (ASGs), Launch Configs, and Launch Templates.

./get-autoscaling.sh --profile admin-cli-sso

get-lambda-inventory.sh

Inventories AWS Lambda functions across all regions.

./get-lambda-inventory.sh --profile admin-cli-sso

get-cloudwatch-logs.sh

Lists CloudWatch Log Groups across all regions, with retention and size info.

./get-cloudwatch-logs.sh --profile admin-cli-sso

get-ecr-repos.sh

Lists all ECR repositories across all regions, including image counts and tags.

./get-ecr-repos.sh --profile admin-cli-sso

get-all-security-groups.sh

Lists all Security Groups across all regions, regardless of attachment state.

./get-all-security-groups.sh --profile admin-cli-sso

get-all-eips.sh

Lists all Elastic IPs across all regions, whether associated or not.

./get-all-eips.sh --profile admin-cli-sso

get-iam-global.sh

Lists IAM SAML providers and virtual MFA devices (global scope).

./get-iam-global.sh --profile admin-cli-sso

get-iam-roles-and-policies.sh

Inventories IAM Roles and managed/inline Policies (global, no regions). Supports enrichment options for attached and inline policy details.

./get-iam-roles-and-policies.sh --profile admin-cli-sso --mode all --include-all

Analysis / Reporting Scripts

get-unattached-ebs.sh

Finds detached EBS volumes that are safe to delete.

./get-unattached-ebs.sh --profile admin-cli-sso

get-unused-security-groups.sh

Identifies security groups not attached to instances or ENIs.

./get-unused-security-groups.sh --profile admin-cli-sso

get-unassociated-eips.sh

Lists Elastic IPs that are allocated but not associated with any resource.

./get-unassociated-eips.sh --profile admin-cli-sso

vpc-blockers.sh

Shows all dependencies within a specific VPC before deletion. Includes optional --include-ec2 flag to list instances inside the VPC.

./vpc-blockers.sh --profile admin-cli-sso --region us-east-1 --vpc vpc-0123abcd4567efgh8

Cleanup / Deletion Scripts

⚠️ Safety first: All deletion scripts default to DRY_RUN=1. To perform real deletions, set DRY_RUN=0 explicitly.


delete-ec2-instance.sh

Terminates a single EC2 instance by ID.

# Preview
./delete-ec2-instance.sh --profile admin-cli-sso --region us-east-1 --instance-id i-0123456789abcdef

# Actually delete
DRY_RUN=0 ./delete-ec2-instance.sh --profile admin-cli-sso --region us-east-1 --instance-id i-0123456789abcdef

delete-unattached-ebs.sh

Deletes detached (unattached) EBS volumes.

# Preview
./delete-unattached-ebs.sh --profile admin-cli-sso --regions us-east-1

# Delete for real
DRY_RUN=0 ./delete-unattached-ebs.sh --profile admin-cli-sso --regions us-east-1

delete-old-snapshots.sh

Deletes snapshots older than a given age (e.g., 30 days).

# Preview
./delete-old-snapshots.sh --profile admin-cli-sso --regions us-east-1 --days 30

# Actually delete
DRY_RUN=0 ./delete-old-snapshots.sh --profile admin-cli-sso --regions us-east-1 --days 30

deregister-old-amis.sh

Deregisters AMIs older than a specified age (days).

# Preview
./deregister-old-amis.sh --profile admin-cli-sso --regions us-east-1 --days 90

# Delete
DRY_RUN=0 ./deregister-old-amis.sh --profile admin-cli-sso --regions us-east-1 --days 90

release-unassociated-eips.sh

Releases all unassociated Elastic IPs.

# Preview
./release-unassociated-eips.sh --profile admin-cli-sso --regions us-east-1

# Actually release
DRY_RUN=0 ./release-unassociated-eips.sh --profile admin-cli-sso --regions us-east-1

delete-detached-igws.sh

Deletes Internet Gateways that are not attached to any VPC.

# Preview
./delete-detached-igws.sh --profile admin-cli-sso --regions us-east-1

# Delete
DRY_RUN=0 ./delete-detached-igws.sh --profile admin-cli-sso --regions us-east-1

delete-unused-sgs.sh

Deletes unused security groups (based on analysis output).

# Preview
./delete-unused-sgs.sh --profile admin-cli-sso --regions us-east-1

# Delete
DRY_RUN=0 ./delete-unused-sgs.sh --profile admin-cli-sso --regions us-east-1

retention-or-delete-log-groups.sh

Sets CloudWatch log group retention and optionally deletes empty ones.

# Preview
./retention-or-delete-log-groups.sh --profile admin-cli-sso --regions us-east-1 --days 30

# Apply retention (and optionally delete empty groups)
DRY_RUN=0 DELETE_EMPTY=1 ./retention-or-delete-log-groups.sh --profile admin-cli-sso --regions us-east-1 --days 14

vpc-teardown.sh

Fully deletes a VPC and all dependencies in correct order.

# Preview
./vpc-teardown.sh --profile admin-cli-sso --region us-east-1 --vpc-id vpc-0123abcd4567efgh8

# Delete
DRY_RUN=0 ./vpc-teardown.sh --profile admin-cli-sso --region us-east-1 --vpc-id vpc-0123abcd4567efgh8

🧱 Default VPCs: The script refuses to delete default VPCs unless explicitly allowed:

bash ALLOW_DEFAULT=1 DRY_RUN=0 ./vpc-teardown.sh --profile admin-cli-sso --region us-east-1 --vpc-id vpc-xxxx


All these resources —

  • VPC
  • Subnets
  • Route Tables
  • Network ACLs
  • Security Groups
  • Internet Gateway
  • DHCP Options Set

— are automatically created by AWS for every region’s default VPC.


Here’s the pattern

When you open a brand-new AWS account, AWS automatically provisions one default VPC per region so you can launch EC2 instances immediately without doing any networking setup.

Each default VPC includes:

Type Count Notes
VPC 1 CIDR like 172.31.0.0/16
Subnets One per AZ E.g. 172.31.0.0/20 per zone
Route Tables 1 main Routes to IGW
Internet Gateway 1 Attached to the VPC
Network ACL 1 Default allow all
Security Group 1 “default” group
DHCP Options Set 1 domain-name = amazonaws.com etc.

Multiply that across each region.

They’re harmless and free unless you have something running inside them (e.g., EC2, RDS, NAT gateway, EIP, etc.).

  • They cost nothing.
  • They exist to make “Launch EC2” just work.

If you want a minimalist account

You can delete them safely using:

ALLOW_DEFAULT=1 DRY_RUN=0 ./vpc-teardown.sh --profile admin-cli-sso --region <region> --vpc-id vpc-xxxx

…for each region where you want to remove the default VPC.

Or simply leave them — they’re perfectly fine to ignore.


delete-s3-bucket.sh

Deletes an S3 bucket (and all objects within it) for a given AWS profile and region.

# Preview (safe mode)
./delete-s3-bucket.sh --profile admin-cli-sso --region us-east-1 --bucket my-temp-bucket

# Actually delete the bucket
DRY_RUN=0 ./delete-s3-bucket.sh --profile admin-cli-sso --region us-east-1 --bucket my-temp-bucket

🧹 Notes:

  • Default behavior is DRY_RUN=1, so nothing is deleted by default.
  • The script empties the bucket first (recursively deletes objects) before removing the bucket.
  • To perform a real deletion, run with DRY_RUN=0.

delete-ecr-images.sh

Deletes images from a specific ECR repository using flexible filters (untagged only, tag prefix, older than N days), keeping the repo intact.

# Preview (safe; shows what would be deleted)
./delete-ecr-images.sh --profile admin-cli-sso --regions us-east-1 --repository my-api --untagged-only 1

# Delete images older than 30 days but keep the newest 5 matching
DRY_RUN=0 ./delete-ecr-images.sh --profile admin-cli-sso --regions us-east-1 --repository my-api --days 30 --keep-latest 5

# Delete images whose tag starts with 'v-'
DRY_RUN=0 ./delete-ecr-images.sh --profile admin-cli-sso --regions "us-east-1 us-west-2" --repository my-api --tag-prefix v-

ecr-prune-untagged.sh

Deletes untagged images across all repositories (optionally limited to specific regions).

# Preview
./ecr-prune-untagged.sh --profile admin-cli-sso --regions "us-east-1 us-west-2"

# Actually prune
DRY_RUN=0 ./ecr-prune-untagged.sh --profile admin-cli-sso

delete-ecr-repo.sh

Deletes an ECR repository; optionally deletes all contained images with --force-images 1.

# Preview
./delete-ecr-repo.sh --profile admin-cli-sso --region us-east-1 --repository my-api

# Delete (force if not empty)
DRY_RUN=0 ./delete-ecr-repo.sh --profile admin-cli-sso --region us-east-1 --repository my-api --force-images 1

Suggested Workflow

  1. Inventory (what do I have?)
./get-all-tagged-resources.sh --profile admin-cli-sso
./get-ec2-instances.sh --profile admin-cli-sso
./get-ec2-network-details.sh --profile admin-cli-sso
./get-ebs-volumes-all.sh --profile admin-cli-sso
./get-s3-buckets.sh --profile admin-cli-sso
./get-rds-inventory.sh --profile admin-cli-sso
./get-elb-inventory.sh --profile admin-cli-sso
  1. Analyze (what’s unused?)
./get-unattached-ebs.sh --profile admin-cli-sso
./get-unused-sgs.sh --profile admin-cli-sso
./get-unassociated-eips.sh --profile admin-cli-sso
./vpc-blockers.sh --profile admin-cli-sso --region us-east-1 --vpc-id vpc-xxxx
  1. Clean up (what can I safely remove?)
DRY_RUN=0 ./delete-unattached-ebs.sh --profile admin-cli-sso --region us-east-1
DRY_RUN=0 ./delete-unused-sgs.sh --profile admin-cli-sso --region us-east-1
DRY_RUN=0 ./release-unassociated-eips.sh --profile admin-cli-sso
DRY_RUN=0 ./delete-old-snapshots.sh --profile admin-cli-sso --region us-east-1 --days 30
DRY_RUN=0 ./deregister-old-amis.sh --profile admin-cli-sso --region us-east-1 --days 90
  1. Teardown (deep cleanup if desired)
./vpc-blockers.sh --profile admin-cli-sso --region us-east-1 --vpc-id vpc-xxxx
DRY_RUN=0 ./vpc-teardown.sh --profile admin-cli-sso --region us-east-1 --vpc-id vpc-xxxx
  1. Verify
./get-all-tagged-resources.sh --profile admin-cli-sso

Best Practices

  • Always run in dry run first (DRY_RUN=1, default).
  • Delete EC2 instances before cleaning up networks or volumes.
  • Avoid deleting default VPCs unless you intentionally want a minimal account.
  • Re-authenticate (aws sso login) if commands start failing unexpectedly.
  • Keep your cleanup scripts under version control for reproducibility.

< Backend Operations - Overview

Next: Backend Observability >