Operational Rules

Your platform standards, applied at terraform init

Terraform's lifecycle blocks can't be passed into upstream modules, so teams fork, wrap, or patch. Operational Rules apply your standards automatically at download time.

The Playground shows the real diff on a real module. No account needed.

The Fork Tax

Terraform doesn't let you pass prevent_destroy or ignore_changes into a module as a variable. It's been an open request since 2018, with hundreds of reactions across related issues. So teams work around it:

Fork every module

Maintain a copy with lifecycle blocks added, re-sync upstream updates manually, repeat for each module.

Write wrapper modules

Another layer of indirection that still needs lifecycle blocks inside.

Add PR review checklists

"Did you add prevent_destroy?" Human memory doesn't scale.

Wire up OPA/Sentinel policies

Can flag a missing lifecycle block, but cannot add one to the code.

Operational Rules handle this at module download time, without forks or wrappers. See what each limit looks like in a real module.

Read the full story on our blog

Known Terraform limits, module by module

A lifecycle block cannot take a variable, so no module in any registry can expose prevent_destroy or ignore_changes as an input. The docs collect the problems this causes in each terraform-aws-modules module: the native workaround first, the rule that answers it where one exists, and the diff the Playground shows. Free to read, free to try.

All modules with known limits

Two Problems, One Product

compliance.tf modules ship with two independent layers applied at download time. Compliance Controls handle regulatory requirements. Operational Rules handle your organizational standards.

Compliance Controls

Audit-ready modules

What it enforces
Regulatory requirements
Driven by
Frameworks (SOC 2, PCI DSS, HIPAA, NIST, ISO 27001...)
Examples
Encryption at rest, access logging, public access blocking
Who configures
compliance.tf (framework-defined)

Operational Rules

Your standards, built in

What it enforces
Organizational standards
Driven by
Platform team decisions
Examples
prevent_destroy, ignore_changes, instance restrictions
Who configures
Org admins (org-defined)

Rule Catalog

The 16 rules in the catalog. Each one is applied at module download time, to every module your organization enables it for. Every rule has a page with the diff it makes, its limits and its failure modes.

Prevent Destroy Data

Adds a lifecycle block to stateful resources so accidental terraform destroy can't wipe production data.

lifecycle { prevent_destroy = true }
S3, RDS instances and clusters, DynamoDB, EFS, ElastiCacheDocs

Ignore Tag Changes

Adds a lifecycle block so external tag changes (AWS Config rules, cost allocation tools, FinOps automation) won't trigger plan diffs.

lifecycle { ignore_changes = [tags, tags_all] }
All taggable resourcesDocs

Ignore Autoscaling Changes

Adds a lifecycle block so DynamoDB auto-scaling doesn't fight with Terraform on every plan.

lifecycle { ignore_changes = [read_capacity, write_capacity] }
DynamoDBDocs

Ignore AMI Changes

Adds a lifecycle block so AMI updates from image pipelines don't cause unexpected instance replacements.

lifecycle { ignore_changes = [ami, image_id] }
EC2 instances, launch templatesDocs

Prevent Destroy Encryption

Adds a lifecycle block to encryption keys and secrets. Losing a KMS key means losing access to everything it encrypted.

lifecycle { prevent_destroy = true }
KMS, Secrets ManagerDocs

No Provisioners

Removes all provisioner blocks from module resources. Provisioners run arbitrary commands outside Terraform's state model and break idempotency.

provisioner blocks removed
All resourcesDocs

Restrict Instance Types

Denies GPU and specialty instance types (p3, p4, x1, x2, u-*) that can generate five- and six-figure monthly bills from a single terraform apply.

denies p3, p4, x1, x2, u-* types
EC2Docs

Allowed Regions

Adds a validation block to the module's region variable so a region outside your organization's allowlist is rejected before anything is created.

validation { condition = contains(allowlist, var.region) }
Modules with a region variableDocs

Ignore Selected Tag Keys

Adds a lifecycle block that ignores only the tag keys your organization names, so scanner or cost tags written outside Terraform stop showing up as drift.

lifecycle { ignore_changes = [tags["<key>"]] }
S3 by defaultDocs

Create Before Destroy

Adds a lifecycle block so a security group or ACM certificate is replaced create-first, and whatever is still attached to the old one keeps working through the swap.

lifecycle { create_before_destroy = true }
Security groups, ACM certificatesDocs

Ignore Deployed Artifacts

Adds a lifecycle block so the zip, image or task definition your pipeline deployed is not rolled back by the next terraform plan.

lifecycle { ignore_changes = [s3_key, image_uri, task_definition] }
Lambda functions, ECS servicesDocs

Ignore Scaling Changes

Adds a lifecycle block so the capacity an autoscaler sets on Auto Scaling groups stops showing as drift. terraform-aws-eks and the terraform-aws-ecs service module already ignore it; the rule covers node groups and services written outside them.

lifecycle { ignore_changes = [desired_capacity] }
Auto Scaling groups; EKS node groups and ECS services outside terraform-aws-modulesDocs

Set EKS Node Group Desired Size

Opt-in. terraform-aws-eks ignores desired_size after create, so Terraform cannot resize a node group. This rule pushes desired, min and max size changes with the AWS CLI from terraform_data, so a min_size raise no longer fails.

resource "terraform_data" "pofix_desired_size" { ... }
EKS managed node groups (terraform-aws-eks)Docs

Ignore Secret Rotation

Adds a lifecycle block so a database password that rotates outside Terraform stops proposing a reset on every plan.

lifecycle { ignore_changes = [password] }
RDS instances, Aurora clustersDocs

Set Deletion Protection

Turns on the provider's deletion protection where a module leaves it unset, so AWS refuses a stray delete from Terraform, the console or the API.

deletion_protection = true
RDS, Aurora, DynamoDB, load balancersDocs

Abort Incomplete Multipart Uploads

Adds a validation to the module's lifecycle_rule variable requiring a rule that aborts incomplete multipart uploads, so parts that are billed but never listed stop accumulating.

validation { abort_incomplete_multipart_upload_days <= 7 }
S3 bucketsDocs

What Module Transformation Looks Like

The Prevent Destroy Data rule applied to an S3 bucket from terraform-aws-modules. This happens at download time, before terraform init completes.

main.tf
resource "aws_s3_bucket" "this" {
  bucket = var.bucket
  # ... existing config ...
+
+ lifecycle {
+   prevent_destroy = true
+ }
}

Each downloaded module includes a manifest with a variant hash identifying the exact transformation that was applied, so you can verify two environments pulled the same rules-applied artifact.

Run this diff yourself in the Rules Playground - real engine, real module, no account. The preview reads the module root only.

Three Steps

1

Configure

Org admins set a Baseline that applies to every module, and named rulesets a single module opts into, from the Operational Rules page in the compliance.tf dashboard or the API.

2

Init

Developers run terraform init with a compliance.tf module source. No new CLI or policy daemon needed.

3

Done

The module arrives with your operational standards already applied. Lifecycle blocks are in the code.

Need to override a rule for a specific download? On a framework host, use per-request query parameters like ?rules=-lifecycle_prevent_destroy_data to drop one of your organization's rules for that download, or ?add_rules=lifecycle_prevent_destroy_data to add one. A bare ?rules= list replaces your rules rather than adding to them, so the two cannot be combined. On your organization's host, select a ruleset with ?ruleset=ignore-scanner-tags.

Shipped, and what's next

Operational Rules ship today. This is where they are, and where they go next.

Rules Preview API and Playground

shipped

See the exact diff a rule makes before you download a module. The Rules Playground runs the public route in the browser with no account; the Preview API guide covers both routes.

Baseline and named rulesets

shipped

A Baseline applies to every module your organization downloads; a named ruleset applies to the modules that select it. Configured from the dashboard or the API, see Baseline rules and rulesets.

Versioned, approved rulesets

planned

Pin a module to an immutable ruleset version and require an approval before a change reaches a download.

Org-authored rules

planned

Write your own transformation rules for org-specific standards.

Start with Hardened Modules Today

Compliance controls and operational rules, applied when you run terraform init. No forks, no wrappers.

No credit card or AWS account needed to start.

Stay Informed About New Features

Join the mailing list for releases, new modules, and roadmap updates. No spam. Unsubscribe anytime.

Not convinced yet, or missing a feature you need? Send us an email - we really want to hear your feedback!