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.
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.
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 }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] }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] }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] }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 }No Provisioners
Removes all provisioner blocks from module resources. Provisioners run arbitrary commands outside Terraform's state model and break idempotency.
provisioner blocks removedRestrict 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-* typesAllowed 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) }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>"]] }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 }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] }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] }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" { ... }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] }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 = trueAbort 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 }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.
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
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.
Init
Developers run terraform init with a compliance.tf module source. No new CLI or policy daemon needed.
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
shippedSee 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
shippedA 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
plannedPin a module to an immutable ruleset version and require an approval before a change reaches a download.
Org-authored rules
plannedWrite 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!