EBS volumes should have encryption at rest enabled
EBS volumes store database files, application state, OS credentials, and temporary data that can outlive the instance they were attached to. Without encryption, anyone with physical access to the underlying storage or access to an unencrypted snapshot can read that data in cleartext. KMS-based encryption at rest costs nothing in throughput on Nitro-based instance types and eliminates an entire class of data exposure.
Enabling account-level default EBS encryption per region prevents engineers from accidentally creating unencrypted volumes. Retrofitting requires snapshot-copy-replace workflows with downtime, which is why enabling the default from day one is worth the effort.
Retrofit consideration
Existing unencrypted volumes cannot be encrypted in place. You must snapshot the volume, create an encrypted copy of the snapshot, then create a new volume from it. This requires detaching the original volume, causing downtime for attached instances.
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 = "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 = "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
}
}
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
The aws_ebs_volume resource must have encrypted = true. Optionally, kms_key_id specifies a customer-managed KMS key ARN; if omitted, the AWS-managed alias/aws/ebs key is used. For volumes created through aws_instance, the encrypted argument within root_block_device and ebs_block_device blocks must also be true.
Alternatively, aws_ebs_encryption_by_default with enabled = true causes all new volumes in the region to be encrypted automatically, but this control evaluates each volume individually. A volume passes when its encrypted attribute is true. It fails when encrypted is false or left unset and no account-level default applies.
Common pitfalls
Account-level default does not retroactively encrypt existing volumes
The account-level default only affects volumes created after it's switched on. Pre-existing unencrypted volumes stay unencrypted and keep failing this control until you run the snapshot-copy replacement workflow on each one.
Root volumes from unencrypted AMIs
An unencrypted AMI produces an unencrypted root volume regardless of your account default, unless you explicitly set
encrypted = truein theroot_block_deviceblock. Useaws_ami_copywithencrypted = trueto create an encrypted copy of the AMI before referencing it in your instance config.Cross-region snapshot copies lose encryption settings
Source-region encryption settings don't carry to the destination when you use
aws_ebs_snapshot_copy. Setencrypted = trueand provide akms_key_idvalid in the target region explicitly, or the copy lands unencrypted.Terraform import of unencrypted volumes forces replacement
Adding
encrypted = trueto an imported unencrypted volume's config won't encrypt it in place. Terraform flags it as a force-replacement, meaning the volume gets destroyed on apply. Plan the data migration before you run it.
Audit evidence
An auditor expects AWS Config rule evaluation results for the managed rule encrypted-volumes, showing all EBS volumes as compliant. The EC2 console Volumes page should display "Encrypted: Yes" for every volume. CloudTrail CreateVolume events should include "encrypted": true in the response element, confirming encryption was applied at creation time.
Security Hub aggregates this finding across accounts and regions into a single artifact. Output from aws ec2 get-ebs-encryption-by-default for each region shows the preventive posture. If customer-managed KMS keys are in use, include key policies and key rotation status from aws kms describe-key in the audit package.
Framework-specific interpretation
GDPR: Article 32 requires appropriate technical measures to protect personal data. Encryption covers the technical-measures requirement. Article 34 is relevant here too: encrypted data that leaks may not trigger the individual notification obligation if it's unintelligible to the recipient.
NIST SP 800-53 Rev 5: SC-28 requires protection of information at rest, and EBS encryption directly satisfies it. When you specify a customer-managed KMS key, you also address SC-12 by demonstrating deliberate key lifecycle governance rather than relying entirely on AWS-managed keys.
NIST Cybersecurity Framework v2.0: EBS encryption at rest maps to PR.DS under the Protect function, covering unauthorized disclosure of stored data if physical or logical access controls are bypassed.
FedRAMP Moderate Baseline Rev 4: At the Moderate baseline, SC-28 applies and federal data on EBS volumes must use FIPS 140-validated cryptographic modules. AWS KMS meets that requirement.
Related controls
SageMaker endpoint configuration encryption should be enabled
Backup plans should have minimum frequency and minimum retention configured
Tool mappings
Use these identifiers to cross-reference this control across tools, reports, and evidence.
Compliance.tf Control:
ebs_volume_encryption_at_rest_enabledAWS Config Managed Rule:
ENCRYPTED_VOLUMESCheckov Checks:
CKV2_AWS_2,CKV_AWS_3Powerpipe Controls:
aws_compliance.control.ebs_attached_volume_encryption_enabled,aws_compliance.control.ebs_volume_encryption_at_rest_enabledProwler Check:
ec2_ebs_volume_encryptionAWS Security Hub Control:
EC2.3KICS Queries:
1f624961-9a18-4387-91c8-3856e1974b6f,cc997676-481b-4e93-aa81-d19f8c5e9b12Trivy Check:
AWS-0026
Last reviewed: 2026-03-09