Skip to content

RDS clusters should have deletion protection enabled

Accidental cluster deletion destroys all automated snapshots and can cause permanent data loss if no manual snapshots exist. Deletion protection adds a deliberate two-step process: an operator must first disable the flag, then issue the delete call. This friction prevents fat-finger mistakes, overly broad IAM teardown scripts, and malicious deletions from compromised credentials.

In production environments running Aurora or DocumentDB, a single aws rds delete-db-cluster call without this guard can wipe hours or days of data that falls between your last manual snapshot and the deletion event. The cost of enabling this setting is zero; the cost of not enabling it is an outage.

Retrofit consideration

Enabling deletion_protection on an existing cluster triggers a modification that applies immediately with no downtime, but Terraform will show a plan diff for every unprotected cluster.

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

module "rds_aurora" {
  source  = "nistcsfv11.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"

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

  deletion_protection = true
}

What this control checks

For aws_rds_cluster resources, deletion_protection must be set to true. When omitted, the AWS provider defaults it to false, and the cluster fails. The same argument applies to aws_docdb_cluster and aws_neptune_cluster resources; the control evaluates those cluster types too. Explicitly set deletion_protection = true on every cluster resource. Either false or an omitted argument is a failing evaluation.

Common pitfalls

  • Default is false when argument is omitted

    The aws_rds_cluster resource defaults deletion_protection to false if you don't declare it. There's no provider-level override to change this default. Every cluster definition needs deletion_protection = true set explicitly.

  • Terraform destroy requires a two-step process

    When deletion_protection = true, terraform destroy will fail: the API rejects the delete call. You'll need to set deletion_protection = false, apply, then destroy. This is intentional, but it catches teams off guard during dev/test teardown.

  • DocumentDB and Neptune clusters evaluated separately

    Findings will appear for aws_docdb_cluster and aws_neptune_cluster resources as well as aws_rds_cluster. Set deletion_protection = true on all three resource types, or suppress the findings in Security Hub for services that are genuinely out of scope.

  • Cluster vs. instance confusion

    Aurora instances (aws_rds_cluster_instance) don't have a deletion_protection argument. The setting lives on aws_rds_cluster only. You can still delete individual instances from a protected cluster; the protection only blocks deleting the cluster itself.

Audit evidence

The primary evidence is AWS Config rule results for rds-cluster-deletion-protection-enabled showing COMPLIANT status across all applicable clusters. aws rds describe-db-clusters output should show "DeletionProtection": true on every cluster object. If Security Hub is in use, there should be no active FAILED findings for this control.

For change-level evidence, CloudTrail ModifyDBCluster and CreateDBCluster events should show DeletionProtection set to true, confirming the setting was applied at provisioning or remediation.

Framework-specific interpretation

NIST Cybersecurity Framework v2.0: PR.DS covers protecting data from loss, corruption, or unauthorized access. Deletion protection is a preventive control directly in scope: it blocks unauthorized or accidental removal of data stored in RDS clusters without requiring any additional tooling.

Tool mappings

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

  • Compliance.tf Control: rds_db_cluster_deletion_protection_enabled

  • AWS Config Managed Rule: RDS_CLUSTER_DELETION_PROTECTION_ENABLED

  • Checkov Check: CKV_AWS_139

  • Powerpipe Control: aws_compliance.control.rds_db_cluster_deletion_protection_enabled

  • Prowler Checks: rds_cluster_deletion_protection, rds_instance_deletion_protection

  • AWS Security Hub Controls: DocumentDB.5, Neptune.4, RDS.7

  • Trivy Checks: AWS-0177, AWS-0343

Last reviewed: 2026-03-09