Skip to content

RDS DB clusters should be encrypted at rest

RDS DB clusters often hold the most sensitive data in an AWS account: customer records, credentials, financial transactions. Without encryption at rest, anyone who gains physical or logical access to the underlying EBS volumes or snapshots can read that data in plaintext. AWS charges nothing extra for RDS encryption, so there is no cost reason to skip it.

The bigger problem is that RDS cluster encryption cannot be toggled on after creation. A cluster launched without storage_encrypted = true must be replaced entirely, which means snapshot, restore to a new encrypted cluster, DNS cutover, and downtime. Catching this at provisioning time eliminates a painful migration later.

Retrofit consideration

RDS cluster encryption is immutable after creation. Enabling it requires creating an encrypted snapshot copy, restoring to a new encrypted cluster, and migrating connections. Expect downtime or a blue-green cutover.

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 "rds_aurora" {
  source  = "nistcsf.compliance.tf/terraform-aws-modules/rds-aurora/aws"
  version = ">=10.0.0,<11.0.0"

  create_db_subnet_group = true
  create_security_group  = true
  engine                 = "aurora-mysql"
  engine_version         = "8.0.mysql_aurora.3.08.0"
  instances = {
    one = {
      instance_class = "db.t4g.medium"
    }
  }
  manage_master_user_password = true
  master_username             = "root"
  name                        = "abc123"
  skip_final_snapshot         = true
  subnets                     = ["subnet-12345678", "subnet-12345678"]
  vpc_id                      = "vpc-12345678"
}

If you use terraform-aws-modules/rds-aurora/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 "rds_aurora" {
  source  = "terraform-aws-modules/rds-aurora/aws"
  version = ">=10.0.0,<11.0.0"

  create_db_subnet_group = true
  create_security_group  = true
  engine                 = "aurora-mysql"
  engine_version         = "8.0.mysql_aurora.3.08.0"
  instances = {
    one = {
      instance_class = "db.t4g.medium"
    }
  }
  manage_master_user_password = true
  master_username             = "root"
  name                        = "abc123"
  skip_final_snapshot         = true
  subnets                     = ["subnet-12345678", "subnet-12345678"]
  vpc_id                      = "vpc-12345678"

  storage_encrypted = true
}

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

resource "aws_rds_cluster" "this" {
  backtrack_window                = 72
  cluster_identifier              = "pofix-abc123"
  db_subnet_group_name            = "example-db-subnet-group"
  enabled_cloudwatch_logs_exports = ["audit"]
  engine                          = "aurora-mysql"
  engine_version                  = "8.0.mysql_aurora.3.08.0"
  manage_master_user_password     = true
  master_username                 = "dbadmin"
  skip_final_snapshot             = true
  vpc_security_group_ids          = ["sg-12345678"]

  storage_encrypted = true
}

What this control checks

The control checks whether the aws_rds_cluster resource has storage_encrypted set to true. It fails when the argument is omitted or explicitly set to false. You can optionally specify a kms_key_id pointing to a customer-managed KMS key ARN; if omitted, AWS falls back to the default aws/rds service key. Either key satisfies the control, provided storage_encrypted = true is present.

Common pitfalls

  • Encryption cannot be enabled post-creation

    Unlike S3 default encryption, RDS cluster encryption is set at creation time and is immutable. If you run terraform apply changing storage_encrypted from false to true on an existing aws_rds_cluster, Terraform will force a destroy and recreate, causing full data loss unless you snapshot and restore manually first.

  • Snapshot copies inherit encryption only when explicitly set

    Copying an unencrypted cluster snapshot with aws rds copy-db-cluster-snapshot produces an unencrypted copy by default. Pass --kms-key-id to encrypt the copy. The aws_db_cluster_snapshot Terraform resource does not support encrypting an unencrypted source, so the migration path typically runs through the CLI.

  • Default KMS key limits cross-account snapshot sharing

    Clusters encrypted with the default aws/rds key cannot share snapshots across AWS accounts. If you need cross-account DR or data sharing, specify a customer-managed kms_key_id with a key policy granting the target account access.

  • Global clusters require encryption on all members

    For Aurora global databases, encryption is configured on each regional aws_rds_cluster member using storage_encrypted and an optional kms_key_id. The aws_rds_global_cluster resource does not set or propagate encryption to member clusters, so don't rely on it to cover this.

Audit evidence

An auditor expects AWS Config rule evaluation results for rds-cluster-encryption-at-rest-enabled (or an equivalent custom rule) returning COMPLIANT for every RDS DB cluster in scope. Supporting evidence includes a CLI export from aws rds describe-db-clusters showing "StorageEncrypted": true and a populated KmsKeyId for each cluster. If a customer-managed KMS key is used, the auditor may also pull the KMS key policy to confirm appropriate access controls.

Screenshots from the RDS console showing the "Encryption" field on each cluster's Configuration tab work as point-in-time evidence. Security Hub dashboards or a third-party CSPM tool extend coverage beyond a snapshot, showing the control held across the full audit period.

Framework-specific interpretation

NIST Cybersecurity Framework v2.0: RDS cluster encryption directly implements PR.DS-1 under the Protect function, which calls for protecting data at rest. NIST CSF v2 treats this as a baseline data security control, not an enhancement, so storage_encrypted = true is the expected starting point for any cluster holding sensitive data.

Tool mappings

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

  • Compliance.tf Control: rds_db_cluster_encryption_at_rest_enabled

  • AWS Config Managed Rule: RDS_CLUSTER_ENCRYPTED_AT_REST

  • Checkov Checks: CKV_AWS_327, CKV_AWS_96

  • Powerpipe Control: aws_compliance.control.rds_db_cluster_encryption_at_rest_enabled

  • Prowler Check: rds_cluster_storage_encrypted

  • AWS Security Hub Control: RDS.27

  • KICS Queries: 1a690d1d-0ae7-49fa-b2db-b75ae0dd1d3e, 3199c26c-7871-4cb3-99c2-10a59244ce7f, 656880aa-1388-488f-a6d4-8f73c23149b2

  • Trivy Check: AWS-0079

Last reviewed: 2026-03-09