Skip to content

RDS DB clusters should be encrypted with CMK

Encrypting RDS DB clusters with a customer-managed KMS key gives you direct control over the key lifecycle: rotation schedules, grant policies, and the ability to revoke access immediately. The default AWS-managed aws/rds key cannot be disabled, deleted, or restricted through your own key policy, which limits your ability to enforce least-privilege access to the underlying data.

CMK-based encryption also enables cross-account audit of key usage through CloudTrail and lets you enforce separation of duties between database administrators and key administrators via distinct IAM policies.

Retrofit consideration

Changing encryption or the KMS key on an existing RDS cluster requires creating an encrypted snapshot, copying it with the new CMK, and restoring a new cluster from that snapshot. This involves downtime and endpoint changes unless you use Aurora cloning or blue-green deployment strategies.

Implementation

Choose the approach that matches how you manage Terraform.

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"
}

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

  kms_key_id = "arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012"
}

What this control checks

The aws_rds_cluster resource must have storage_encrypted = true and kms_key_id pointing to the ARN of a customer-managed KMS key (created via aws_kms_key, not the default aws/rds managed key). If kms_key_id is omitted, AWS defaults to aws/rds, which fails this control. If storage_encrypted is false or unset, the cluster is unencrypted and fails as well. Both arguments must be present and correctly set for the control to pass.

Common pitfalls

  • AWS-managed key passes encryption check but fails CMK check

    Setting storage_encrypted = true without specifying kms_key_id causes AWS to use the default aws/rds managed key. The cluster is encrypted, but this control still fails because the key is not customer-managed.

  • KMS key deletion makes cluster inaccessible

    If the CMK referenced by kms_key_id is scheduled for deletion or disabled, the RDS cluster becomes inaccessible. Add a prevent_destroy lifecycle rule to the aws_kms_key resource and set deletion_window_in_days to at least 7, ideally 30.

  • Cross-region replicas require a separate CMK

    KMS keys are region-scoped. Cross-region read replicas and global clusters each need a CMK ARN in the target region, passed via the replica's kms_key_id. Leave it out and the replica silently falls back to the aws/rds key in that region, which fails this control.

  • Encryption cannot be added to an existing unencrypted cluster in place

    There is no modify-db-cluster option to enable encryption on a running cluster. The path forward: snapshot, copy with aws rds copy-db-cluster-snapshot --kms-key-id <cmk-arn>, then restore. Terraform will plan a destroy/create cycle, so coordinate the cutover with a maintenance window and an endpoint update.

Audit evidence

Auditors expect Config rule evaluation results showing each AWS::RDS::DBCluster resource as COMPLIANT, with StorageEncrypted set to true and KmsKeyId referencing a customer-managed key ARN. Those ARNs should be cross-referenced against the KMS console or aws kms describe-key output to confirm the key's KeyManager field is CUSTOMER, not AWS.

CloudTrail logs for kms:Decrypt and kms:GenerateDataKey calls from the RDS service principal provide additional evidence the CMK is actively in use. KMS key policies should be on hand to demonstrate restricted access and a rotation configuration.

Framework-specific interpretation

Tool mappings

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

  • Compliance.tf Control: rds_db_cluster_encrypted_with_cmk

  • AWS Config Managed Rule: RDS_CLUSTER_ENCRYPTED_AT_REST

  • Checkov Check: CKV_AWS_327

  • Powerpipe Control: aws_compliance.control.rds_db_cluster_encrypted_with_cmk

  • Prowler Check: rds_cluster_storage_encrypted

  • AWS Security Hub Control: RDS.27

Last reviewed: 2026-03-09