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:
- 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
- Login with SSO:
aws sso login --profile admin-cli-sso
- Install jq (for JSON parsing):
brew install jq # macOS
sudo apt install jq # Ubuntu/Debian
- 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, setDRY_RUN=0explicitly.
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¶
- 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
- 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
- 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
- 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
- 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 >