Back to blog
AWSBest PracticesCloud SecurityCost OptimizationStorage

AMI Not In Use: Cleaning Up Orphaned Amazon Machine Images

Unused AMIs keep their EBS snapshots alive, raising costs and security risk. Learn how to find, deregister, and prevent orphaned Amazon Machine Images in AWS.

TL;DR

This check flags AMIs that no running instance or launch template references. Unused AMIs keep their backing EBS snapshots alive, quietly running up your bill and widening your attack surface. Deregister the AMI and delete its snapshots once you confirm nothing depends on it.

AMIs pile up. Every time you bake a golden image, run a Packer build, or back up an instance, you create another Amazon Machine Image and a set of EBS snapshots underneath it. Most teams are good at creating images and terrible at cleaning them up. The result is an account full of AMIs that no instance boots from and no launch template points to.

The ebs_unusedami check catches exactly this situation: an AMI you own that nothing in your account is actively using.


What this check detects

Lensix looks at every AMI your account owns and cross-references it against two things:

  • The image ID of every running and stopped EC2 instance
  • The image ID referenced in every launch template version and launch configuration

If an AMI is not referenced by any instance or any launch template, it is reported as unused. The check is scoped to images you own, not public or AWS-provided AMIs that you have never copied into your account.

Note: An AMI is mostly metadata. The real storage cost lives in the EBS snapshots the AMI points to. When you register an AMI, AWS creates one snapshot per block device. Deregistering the AMI does not automatically delete those snapshots, which is why orphaned snapshots are such a common source of waste.


Why it matters

You are paying for storage you forgot about

Each AMI keeps its EBS snapshots, and EBS snapshots are billed per GB-month of changed data. A single 100 GB image is not much. A few hundred of them across regions, accumulated over years of CI builds and ad hoc backups, turns into a line item that nobody can explain. This is one of the most common forms of silent cloud waste.

Stale images are a security liability

An AMI is a frozen point in time. The packages, kernel, and configuration baked into it stop receiving updates the moment it is created. If someone launches an instance from a two-year-old image because it was still sitting in the list, they have just deployed a host full of known CVEs. Old images also sometimes contain things they should not: hardcoded credentials, internal certificates, or application secrets that were present when the image was baked.

Warning: Before you delete an old AMI, check whether anyone can launch from it. Shared AMIs and images referenced in another account's launch templates will not show up when you only inspect your own instances. Audit launch permissions before deregistering.

Clutter slows down incident response

When you need to roll back to a known-good image during an outage, scrolling through 300 AMIs with names like backup-2022-final-v2 wastes time you do not have. A tidy image catalog is an operational asset.


How to fix it

The fix is two steps: deregister the AMI, then delete the snapshots that backed it. Confirm the AMI is genuinely unused first.

Step 1: Confirm nothing references the AMI

Check for instances using the image:

AMI_ID=ami-0123456789abcdef0

aws ec2 describe-instances \
  --filters "Name=image-id,Values=$AMI_ID" \
  --query "Reservations[].Instances[].InstanceId" \
  --output text

Check launch templates across all versions:

for LT in $(aws ec2 describe-launch-templates \
  --query "LaunchTemplates[].LaunchTemplateId" --output text); do
  aws ec2 describe-launch-template-versions \
    --launch-template-id "$LT" \
    --query "LaunchTemplateVersions[?LaunchTemplateData.ImageId=='$AMI_ID'].[LaunchTemplateId,VersionNumber]" \
    --output text
done

Also check who you have shared it with:

aws ec2 describe-image-attribute \
  --image-id "$AMI_ID" \
  --attribute launchPermission

Step 2: Record the snapshot IDs before you deregister

Once you deregister, the mapping between the AMI and its snapshots is gone, so grab the snapshot IDs first.

aws ec2 describe-images \
  --image-ids "$AMI_ID" \
  --query "Images[].BlockDeviceMappings[].Ebs.SnapshotId" \
  --output text

Step 3: Deregister the AMI and delete the snapshots

Danger: Deregistering an AMI is irreversible. You cannot launch new instances from it afterward, and recreating it means rebuilding the image from scratch. Make sure no autoscaling group, launch template, or disaster recovery runbook depends on it before you run these commands.

# Deregister the AMI
aws ec2 deregister-image --image-id "$AMI_ID"

# Delete each snapshot that backed it
aws ec2 delete-snapshot --snapshot-id snap-0123456789abcdef0

Console steps

  1. Open the EC2 console and go to Images > AMIs.
  2. Select the AMI, choose Actions > Deregister AMI, and confirm.
  3. Go to Elastic Block Store > Snapshots.
  4. Find the snapshots by the description AWS auto-generates (it includes the AMI ID), select them, and choose Actions > Delete snapshot.

Tip: If you manage images with Terraform, do not delete them by hand. Remove the aws_ami or aws_ami_copy resource from your configuration and let terraform apply deregister it. Deleting out of band leaves your state file out of sync and causes confusing drift on the next plan.


How to prevent it from happening again

Use EC2 Image Builder lifecycle policies

EC2 Image Builder supports lifecycle policies that automatically deregister AMIs and delete their snapshots based on age or count. If your pipeline produces an image on every build, a policy that keeps the last five and removes the rest stops the pile-up before it starts.

Tag images at creation so cleanup is automatable

An image you cannot reason about is an image nobody will ever delete. Tag every AMI with an owner, a creation date, and a retention intent at build time.

{
  "Owner": "platform-team",
  "CreatedBy": "packer-pipeline",
  "ExpiresAfter": "2024-12-31",
  "Purpose": "base-ubuntu-22.04"
}

Run a scheduled cleanup with Lambda

A small scheduled function can find AMIs older than your retention window that no instance or launch template references and either alert or deregister them. The query logic is the same as the confirmation steps above. Run it in dry-run mode first, send the candidates to Slack, and only enable deletion once you trust the output.

Gate AMI sprawl in CI/CD

If a Packer build runs on every merge, add a post-build step that prunes old image versions. Packer's post-processor hooks or a follow-up CLI step can deregister anything beyond the latest N builds for that image family.

Tip: Continuous monitoring closes the loop. Lensix re-runs the ebs_unusedami check on every scan, so a stale image that slips past your lifecycle policy gets flagged within hours instead of surfacing during a cost review six months later.


Best practices

  • Treat AMIs as cattle, not pets. They should be reproducible from a Packer or Image Builder pipeline, so deleting one carries no fear.
  • Always clean up the snapshots, not just the AMI. Deregistering the image alone leaves the storage cost in place. Orphaned snapshots are their own common Lensix finding.
  • Set a retention policy and write it down. "Keep the last five production images and 30 days of build artifacts" is a policy you can automate. "Delete when someone notices" is not.
  • Audit launch permissions periodically. An AMI shared with accounts you no longer work with is both a security and a billing concern.
  • Sweep every region. AMIs are regional. A cleanup script that only checks us-east-1 misses the copies your DR setup pushed to other regions.
  • Pin AMI IDs in IaC and update them deliberately. Referencing the latest image dynamically can keep old ones technically unused yet hard to retire safely. Explicit references make dependencies visible.

Unused AMIs are low-stakes individually and expensive in aggregate. Knock them out on a schedule, automate the cleanup, and your image catalog stays small enough to actually trust during an incident.