Skip to content

EC2 instances should have attached EBS volumes marked for deletion on termination

Orphaned EBS volumes left behind after instance termination create two problems: cost and data exposure. Each undeleted volume continues accruing storage charges (gp3 costs $0.08/GB-month), and volumes containing application data, credentials, or database files persist indefinitely without the access controls the original instance provided.

Teams running auto-scaling groups or ephemeral workloads are especially exposed. A single scaling event that launches and terminates 50 instances can leave 50 untracked volumes behind. Over weeks, these accumulate into significant spend and a growing attack surface that nobody monitors.

Retrofit consideration

Volumes attached via aws_volume_attachment have no delete_on_termination argument in Terraform. Retrofitting means either switching to inline ebs_block_device blocks on aws_instance, or setting the flag out-of-band via aws ec2 modify-instance-attribute after attachment.

Implementation

Choose the approach that matches how you manage Terraform.

If you use terraform-aws-modules/ec2-instance/aws, set the right module inputs for this control. You can later migrate to the compliance.tf module with minimal changes because it is compatible by design.

module "ec2_instance" {
  source  = "terraform-aws-modules/ec2-instance/aws"
  version = ">=6.0.0"

  ami_ssm_parameter = "/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-arm64"
  instance_type     = "t4g.nano"
  subnet_id         = "subnet-abc123"

  root_block_device = {
    delete_on_termination = true
  }
}

Use AWS provider resources directly. See docs for the resources involved: aws_instance.

resource "aws_instance" "this" {
  ami                    = "ami-abc12345"
  instance_type          = "t4g.nano"
  subnet_id              = element(["subnet-abc123", "subnet-def456"], 0)
  vpc_security_group_ids = ["sg-abc12345"]

  root_block_device {
    delete_on_termination = true
  }
}

What this control checks

The control checks that every EBS volume in an EC2 instance's block device mapping has delete_on_termination set to true. In Terraform, aws_instance exposes this through root_block_device and ebs_block_device blocks. The root block device defaults to deleted on termination, but non-root EBS mappings need to be set explicitly. If delete_on_termination is false or absent on any non-root mapping, the control fails.

The trickier case: volumes managed as separate aws_ebs_volume resources attached via aws_volume_attachment default to DeleteOnTermination = false in the underlying block device mapping. aws_volume_attachment has no delete_on_termination argument, so this pattern fails the control unless you set the attribute through an aws ec2 modify-instance-attribute call or a local-exec provisioner post-attachment. When the volume lifecycle should follow the instance, use inline ebs_block_device blocks on aws_instance.

Common pitfalls

  • aws_volume_attachment defaults DeleteOnTermination to false

    Attach a volume through aws_ebs_volume plus aws_volume_attachment and AWS sets DeleteOnTermination to false on the resulting block device mapping. Terraform offers no argument on aws_volume_attachment to override this, so the only paths forward are switching to inline ebs_block_device blocks on aws_instance, or calling aws ec2 modify-instance-attribute after attachment to flip the flag.

  • Launch templates may override instance-level settings

    For instances launched via aws_launch_template, the block_device_mappings.ebs.delete_on_termination value in the template is what controls the flag, not anything on the instance resource itself. A template that omits the ebs block or explicitly sets delete_on_termination = false produces non-compliant instances regardless of what the rest of your Terraform looks like.

  • AMI-baked block device mappings can carry forward false

    If you're launching from a custom AMI built with aws_ami_from_instance, check the source instance's secondary volume mappings before publishing it. Custom AMIs inherit block device behavior from the source, so if delete_on_termination was false on a secondary volume, every instance launched from that AMI carries the same setting unless you explicitly override it in the ebs_block_device block or launch template.

  • Terraform plan does not detect out-of-band flag changes

    Change DeleteOnTermination to false via the Console or CLI on a running instance, and Terraform won't know. Block device mapping drift is invisible to terraform plan unless the configuration is managed inline. Periodic aws ec2 describe-instances checks or a Config rule are the only reliable way to catch it.

Audit evidence

Auditors expect Config rule evaluation results showing compliant status for every in-scope EC2 instance, from either a managed rule or a custom rule checking DeleteOnTermination across running instances. Supporting evidence is the output of aws ec2 describe-instances filtered to the BlockDeviceMappings array, with each entry's Ebs.DeleteOnTermination field reading true.

For ongoing assurance, a Config conformance pack report or compliance dashboard showing continuous compliance across accounts and regions covers the control over time. CloudTrail logs for RunInstances and AttachVolume calls can confirm no volumes were attached with the flag set to false.

Tool mappings

Use these identifiers to cross-reference this control across tools, reports, and evidence.

  • Compliance.tf Control: ec2_instance_attached_ebs_volume_delete_on_termination_enabled

  • Powerpipe Controls: aws_compliance.control.ebs_attached_volume_delete_on_termination_enabled, aws_compliance.control.ec2_instance_attached_ebs_volume_delete_on_termination_enabled

Last reviewed: 2026-03-09