Skip to content

Attached EBS volumes should have encryption enabled

EBS volumes frequently store operating system swap files, application logs, database journals, and temporary processing data containing sensitive information. Without encryption, that data sits on shared physical storage hardware in plaintext, exposed to risks from improper disk decommissioning or unauthorized snapshot copying.

Encryption at the volume level costs nothing extra in AWS and adds negligible latency on modern Nitro-based instances. Leaving it off is a pure oversight with real consequences, especially when a volume gets snapshotted and shared across accounts.

Retrofit consideration

Existing unencrypted EBS volumes cannot be encrypted in place. You must create an encrypted snapshot, create a new encrypted volume from that snapshot, detach the old volume, and attach the new one. This requires instance downtime or careful live-migration planning. For root volumes, the instance must be stopped.

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"

  ebs_volumes = {
    encrypted = true
  }
}

module "ec2_instance" {
  source  = "pcidss.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"

  ebs_volumes = {
    encrypted = true
  }
}

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"

  ebs_volumes = {
    encrypted = true
  }
}

module "ec2_instance" {
  source  = "gdpr.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"

  ebs_volumes = {
    encrypted = true
  }
}

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"

  ebs_volumes = {
    encrypted = true
  }
}

module "ec2_instance" {
  source  = "nistcsf.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"

  ebs_volumes = {
    encrypted = true
  }
}

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"

  ebs_volumes = {
    encrypted = true
  }
}

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"

  ebs_volumes = {
    encrypted = true
  }
}

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"

  ebs_volumes = {
    encrypted = true
  }
}

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"

  ebs_volumes = {
    encrypted = true
  }
}

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"

  ebs_volumes = {
    encrypted = true
  }
}

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"

  ebs_volumes = {
    encrypted = true
  }
}

module "ec2_instance" {
  source  = "cisv140.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"

  ebs_volumes = {
    encrypted = true
  }
}

module "ec2_instance" {
  source  = "ffiec.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"

  ebs_volumes = {
    encrypted = true
  }
}

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"

  ebs_volumes = {
    encrypted = true
  }
}

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"

  ebs_volumes = {
    encrypted = true
  }
}

module "ec2_instance" {
  source  = "rbicybersecurity.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"

  ebs_volumes = {
    encrypted = true
  }
}

module "ec2_instance" {
  source  = "cisv130.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"

  ebs_volumes = {
    encrypted = true
  }
}

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"

  ebs_volumes = {
    encrypted = true
  }
}

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"

  ebs_volumes = {
    encrypted = true
  }
}

module "ec2_instance" {
  source  = "nist80053rev4.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"

  ebs_volumes = {
    encrypted = true
  }
}

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"

  ebs_volumes = {
    encrypted = true
  }
}

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_volumes = {
    encrypted = true
  }
}

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

resource "aws_ebs_volume" "this" {
  availability_zone = local.availability_zone
  size              = 10

  encrypted = true
}

What this control checks

This control validates that every aws_ebs_volume resource and every inline ebs_block_device or root_block_device block within aws_instance or aws_launch_template has encrypted set to true. A volume passes when encrypted = true is explicitly configured, either using the default aws/ebs service key or a customer-managed KMS key via kms_key_id. It fails when encrypted is omitted (defaults to false unless the account-level default encryption setting overrides it) or explicitly set to false. To enforce this broadly without per-resource configuration, enable account-level EBS encryption via aws_ebs_encryption_by_default and optionally set aws_ebs_default_kms_key, but the control still evaluates the resulting encryption state on each attached volume.

Common pitfalls

  • Account default encryption does not retroactively encrypt existing volumes

    Enabling aws_ebs_encryption_by_default only affects volumes created after the setting is turned on. Pre-existing unencrypted volumes remain unencrypted and will still fail this control. You must migrate them manually.

  • Inline ebs_block_device blocks may silently omit encryption

    When using ebs_block_device inside aws_instance instead of separate aws_ebs_volume and aws_volume_attachment resources, encrypted defaults to false if not specified. This is easy to miss in large instance definitions with several block devices.

  • Snapshots from unencrypted volumes create unencrypted volumes by default

    Restore a volume from an unencrypted snapshot using aws_ebs_volume with snapshot_id and you get an unencrypted volume unless you explicitly set encrypted = true. EBS re-encrypts the data during the copy operation, which requires a KMS key to be available.

  • Multi-region KMS key availability

    A kms_key_id referencing a KMS key from a different region will cause volume creation to fail outright. Each region needs its own KMS key or a multi-region replica key configured before the volume is provisioned.

  • Launch templates may override encryption settings

    An aws_launch_template with block_device_mappings can set encrypted = false on an ebs block, overriding the account default. Get this wrong and Auto Scaling groups using that template will produce non-compliant volumes at scale before anyone notices.

Audit evidence

An auditor expects Config rule evaluation results for the managed rule ENCRYPTED_VOLUMES, showing all attached EBS volumes as COMPLIANT. Supporting evidence includes an EC2 console screenshot of the volume list filtered to "in-use" state with the "Encrypted" column showing "Yes" for every entry. CloudTrail CreateVolume and AttachVolume events can confirm that encryption was specified at creation time.

For stronger evidence, provide the output of aws ec2 describe-volumes --filters Name=attachment.status,Values=attached --query "Volumes[?Encrypted==\false`]"returning an empty list, along with confirmation thataws ec2 get-ebs-encryption-by-defaultreturnsEbsEncryptionByDefault: true` for each region in scope.

Framework-specific interpretation

SOC 2: CC6 and CC7 both call for logical and technical safeguards protecting data at rest. Encrypted EBS volumes are a standard control activity auditors look for during walkthroughs of EC2-based workloads, and the absence of encryption is a straightforward finding.

PCI DSS v4.0: Requirement 3.4 says PAN must be rendered unreadable wherever it is stored. EBS encryption with proper key management is one way to satisfy this for cardholder data on block storage, though key access controls matter as much as the encryption itself.

HIPAA Omnibus Rule 2013: 45 CFR 164.312(a)(2)(iv) lists encryption as an addressable specification for ePHI at rest. Addressable doesn't mean optional: any EBS volume attached to an instance processing ePHI needs encryption enabled, or you must document an equivalent alternative safeguard and formally accept the risk. In practice, there is no reasonable equivalent when AWS provides native encryption at no additional cost.

GDPR: Article 32 requires appropriate technical measures to protect personal data, and encryption is explicitly cited as an example. Encrypting EBS volumes storing EU personal data reduces breach impact and can factor into the Article 34(3)(a) exemption from notification obligations when the data remains unintelligible to unauthorized parties.

NIST SP 800-53 Rev 5: SC-28 requires cryptographic mechanisms to prevent unauthorized disclosure and modification of data stored on digital media. EBS volume encryption with AES-256 through KMS satisfies this for block storage.

NIST Cybersecurity Framework v2.0: EBS encryption maps to PR.DS, the data security subcategory covering protection of data at rest. When physical media is compromised or a snapshot is copied without authorization, an encrypted volume is unreadable without access to the KMS key.

FedRAMP Moderate Baseline Rev 4: At the Moderate baseline, SC-28 applies to federal data stored on EBS volumes. EBS encryption through KMS uses FIPS 140-2 validated cryptographic modules, which is what FedRAMP needs for approved mechanisms under this control.

Tool mappings

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

  • Compliance.tf Control: ebs_attached_volume_encryption_enabled

  • AWS Config Managed Rule: ENCRYPTED_VOLUMES

  • Checkov Checks: CKV2_AWS_2, CKV_AWS_3

  • Powerpipe Controls: aws_compliance.control.ebs_attached_volume_encryption_enabled, aws_compliance.control.ebs_volume_encryption_at_rest_enabled

  • Prowler Check: ec2_ebs_volume_encryption

  • AWS Security Hub Control: EC2.3

  • KICS Queries: cc997676-481b-4e93-aa81-d19f8c5e9b12, e6b4b943-6883-47a9-9739-7ada9568f8ca

  • Trivy Checks: AWS-0026, AWS-0131

Last reviewed: 2026-03-09