Prevent Destroy Data
Adds prevent_destroy = true to data-bearing resources, blocking accidental deletion.
When to use this rule
Use this when: Your modules manage S3 buckets, RDS databases, DynamoDB tables, or EFS file systems that hold production data.
Do not use this when: You run ephemeral test environments where resources are destroyed after each CI run, or you are actively migrating data and need to delete old resources.
Why this rule exists
Accidentally destroying an S3 bucket, RDS instance, DynamoDB table, or EFS file system can cause data loss that is difficult or impossible to recover from. A single terraform destroy or a careless resource rename can trigger deletion of production data.
Terraform's prevent_destroy lifecycle argument is the built-in safeguard. But it cannot be passed as a variable into a module. Every team using upstream terraform-aws-modules must either fork the module to add it, or rely on review checklists.
Related Terraform and OpenTofu issues
| Repository | Issue | Title |
|---|---|---|
| hashicorp/terraform | #3116 | Cannot use interpolations in lifecycle attributes |
| hashicorp/terraform | #18367 | Feature request: support prevent_destroy for modules |
| hashicorp/terraform | #27360 | A method to override configuration and meta arguments within a module |
Affected resources
| Resource | Service | Why |
|---|---|---|
aws_s3_bucket | Amazon S3 | Object storage for logs, backups, application data |
aws_db_instance | Amazon RDS | Relational databases with primary application data |
aws_dynamodb_table | Amazon DynamoDB | NoSQL tables for application state and session data |
aws_efs_file_system | Amazon EFS | Shared file storage mounted by compute workloads |
Known limits
- Does not cover
aws_rds_cluster(Aurora),aws_redshift_cluster,aws_elasticache_cluster,aws_neptune_cluster, or any other stateful resource not listed in affected resources. - Does not prevent deletion of S3 objects inside the bucket, only the bucket resource itself.
- Does not apply to child/nested modules called by the protected module.
What this rule does
Adds a lifecycle { prevent_destroy = true } block to each matching resource. Terraform and OpenTofu will refuse to destroy these resources during terraform destroy or resource replacement.
Before and after
resource "aws_s3_bucket" "this" {
# ... resource configuration ...
tags = var.tags
}
resource "aws_s3_bucket" "this" {
# ... resource configuration ...
tags = var.tags
lifecycle {
prevent_destroy = true
}
}
The only change is the rule transformation. All existing arguments, outputs, and module behavior remain identical.
Real-world scenario
A developer renamed an S3 bucket variable during refactoring. Without prevent_destroy, terraform apply deleted the production bucket containing 3 years of audit logs and created a new empty one.
Compliance framework support
This rule is not a compliance control. It supports these framework objectives as an operational safeguard:
| Framework | Controls | Role |
|---|---|---|
| SOC 2 | CC6.1, CC7.2 | Supports data protection and availability objectives |
| NIST 800-53 | CP-9, SI-12 | Supports backup and information management |
Default configuration
This rule ships with the following defaults. Custom parameterization via the registry is planned for a future release.
| Parameter | Type | Default | Description |
|---|---|---|---|
resource_types | list(string) | ["aws_s3_bucket", "aws_db_instance", "aws_dynamodb_table", "aws_efs_file_system"] | Data-storage resource types to protect |
How to enable
Add ?rules=pofix/prevent_destroy_data to your HTTPS module source:
module "example" {
source = "https://soc2.compliance.tf/terraform-aws-modules/s3-bucket/aws?version=5.0.0&rules=pofix/prevent_destroy_data"
}
Configure via the compliance.tf API. See Getting Started with Operational Rules.
Break-glass path
Use ?rules=-pofix/prevent_destroy_data in the module source URL to download without this rule for a single terraform init.
Failure modes
| Scenario | Result |
|---|---|
| Rule targets a module with no matching resource types | No-op. Module is delivered unchanged. No error. |
Developer runs terraform destroy on a protected resource | Terraform exits with error: "Instance cannot be destroyed because of prevent_destroy." |
| Resource rename causes replacement plan | Terraform will error on destroy of the old resource. Use terraform state mv to rename without destroy. |
Terraform and OpenTofu compatible
This rule works with both Terraform (1.x+) and OpenTofu (1.6+). The generated HCL uses standard lifecycle meta-arguments supported by all versions.
Help us improve this page
Operational Rules are a new feature. We'd love your feedback on this rule page — what's useful, what's missing, what's confusing. Share feedback.