Skip to content

EC2 instances should have EBS optimization enabled

Without EBS optimization, storage I/O shares bandwidth with regular network traffic on the instance. Under heavy load, this contention causes unpredictable latency spikes and throughput drops for both EBS volumes and network operations. Workloads that depend on consistent disk performance (databases, analytics pipelines, log aggregation) can experience degraded throughput that is difficult to diagnose because it correlates with unrelated network activity rather than storage load.

Many newer instance families (m5, c5, r5, and later generations) are EBS-optimized by default, but explicitly setting the flag ensures the behavior is intentional and survives instance type changes during refactoring.

Retrofit consideration

Enabling EBS optimization on older instance types (c3, m3, r3) may require a stop/start cycle and could change the instance's network throughput allocation. Verify your instance type supports EBS optimization before applying.

Implementation

Choose the approach that matches how you manage Terraform.

Use the compliance.tf module to enforce this control by default. See get started with compliance.tf.

module "ec2_instance" {
  source  = "soc2.compliance.tf/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"
}

module "ec2_instance" {
  source  = "hipaa.compliance.tf/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"
}

module "ec2_instance" {
  source  = "nist80053.compliance.tf/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"
}

module "ec2_instance" {
  source  = "fedrampmoderate.compliance.tf/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"
}

module "ec2_instance" {
  source  = "cisv80ig1.compliance.tf/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"
}

module "ec2_instance" {
  source  = "nist800171.compliance.tf/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"
}

module "ec2_instance" {
  source  = "awscontroltower.compliance.tf/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"
}

module "ec2_instance" {
  source  = "cisacyberessentials.compliance.tf/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"
}

module "ec2_instance" {
  source  = "nydfs23.compliance.tf/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"
}

module "ec2_instance" {
  source  = "eugmpannex11.compliance.tf/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"
}

module "ec2_instance" {
  source  = "cfrpart11.compliance.tf/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"
}

module "ec2_instance" {
  source  = "rbiitfnbfc.compliance.tf/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"
}

module "ec2_instance" {
  source  = "fedramplow.compliance.tf/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"
}

module "ec2_instance" {
  source  = "hipaasecurity2003.compliance.tf/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"
}

module "ec2_instance" {
  source  = "nistcsfv11.compliance.tf/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"
}

module "ec2_instance" {
  source  = "pcidssv321.compliance.tf/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"
}

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"

  ebs_optimized = 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"]

  ebs_optimized = true
}

What this control checks

This control validates that the aws_instance resource has ebs_optimized set to true. If omitted, plan state and the live API can diverge by instance type: newer families (m5, c5, r5, c6i, m6g, etc.) are EBS-optimized by default at the AWS level, but Terraform records the attribute as false when not explicitly set. The control expects the explicit argument regardless. Setting ebs_optimized = false fails; omission may also fail depending on whether the policy engine reads the configured value or the computed AWS state.

Common pitfalls

  • Instance types that do not support EBS optimization

    Before setting ebs_optimized = true, confirm the instance type supports it. Older types like m3.medium will return an API error during terraform apply. Use aws ec2 describe-instance-types --filters Name=ebs-info.ebs-optimized-support,Values=supported,default to check, or consult the AWS instance type documentation.

  • Default-optimized instances may still report false in state

    Omit ebs_optimized on an m5 or c5, and AWS reports EbsOptimized: true at the API level while Terraform records false in state. Compliance tooling that reads Terraform state rather than the live AWS API will flag these instances as non-compliant even though the hardware is behaving correctly. Explicit is better.

  • Launch templates override instance-level settings

    If an aws_launch_template includes ebs_optimized, that setting takes precedence over what is on the aws_instance resource. Set ebs_optimized = true in the aws_launch_template block directly, not only on the instance definition.

  • Cost implications on older generations

    On some older instance families (c3, m3, r3), EBS optimization has historically carried a per-hour surcharge. Most current instance types include it at no extra cost, but check regional EC2 pricing before bulk-enabling across a fleet of legacy instances.

Audit evidence

AWS Config evaluation results for the ebs-optimized-instance managed rule are the primary artifact. Supporting evidence includes the EC2 console Instances view with the 'EBS optimized' column visible, or aws ec2 describe-instances output filtered on EbsOptimized: true for all running instances. For organizations running scheduled compliance scans, Config compliance timeline snapshots show sustained adherence across the audit period, not just a point-in-time screenshot.

Framework-specific interpretation

SOC 2: SOC 2 A1 (Availability) and related common criteria (CC3, CC7) call for infrastructure that maintains predictable performance under load. Shared I/O bandwidth is a source of availability risk; EBS optimization eliminates it.

HIPAA Omnibus Rule 2013: 45 CFR 164.312 requires covered entities to ensure the availability of ePHI systems. Storage I/O contention during peak load is a real availability risk, and for EC2 workloads, EBS optimization removes it.

NIST SP 800-53 Rev 5: Dedicated EBS throughput directly addresses SC-6 (Resource Availability) in NIST 800-53 Rev 5. Without it, a busy instance can saturate shared bandwidth and degrade both storage and network performance simultaneously, which is the resource contention scenario SC-6 controls are designed to prevent.

FedRAMP Moderate Baseline Rev 4: SC-6 requires federal systems to protect the availability of processing and communication resources. For EBS-backed workloads, dedicated I/O throughput is how you meet that requirement: shared-bandwidth contention under load is exactly the kind of resource exhaustion SC-6 is designed to prevent.

Tool mappings

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

  • Compliance.tf Control: ec2_instance_ebs_optimized

  • AWS Config Managed Rule: EBS_OPTIMIZED_INSTANCE

  • Checkov Check: CKV_AWS_135

  • Powerpipe Control: aws_compliance.control.ec2_instance_ebs_optimized

  • KICS Query: 60224630-175a-472a-9e23-133827040766

Last reviewed: 2026-03-09