Sign in
Menu
Sign up
Docs
Operational rules

Rules overview

For platform and security engineers deciding whether Operational Rules fit their estate. This page explains what rules are, how they reach a module, and how they relate to compliance controls. To apply one, go to Add your first rule.

  • Operational Rules transform your Terraform modules at download time to apply your organization's operational standards.
  • Rules handle lifecycle blocks, tagging, provisioner removal, and instance type restrictions.
  • No forks, no wrapper modules. Same terraform init, same modules.
  • Rules and compliance controls are independent layers. Controls run first, then rules. Changes are merged additively.
  • On your organization's host, rules come from a Baseline that applies to every module and named rulesets a module selects with ?ruleset=.

The problem rules solve

Terraform's lifecycle meta-argument cannot be parameterized. You cannot pass prevent_destroy = true into an upstream module as a variable, and a module has no way to accept one. The request to allow it (hashicorp/terraform#3116) was closed in 2023 without a change; among the open requests are hashicorp/terraform#18367, hashicorp/terraform#22544 and opentofu/opentofu#1329. The per-module pages under Workarounds list where this bites in terraform-aws-modules and what the native workaround is.

When a platform team needs prevent_destroy on S3 buckets, ignore_changes on tags, and no provisioner blocks, they respond with one of these workarounds:

  • Fork the module. Maintain a copy with lifecycle blocks added. Repeat for every module. Sync upstream updates manually.
  • Write wrapper modules. Add a layer of indirection that still needs lifecycle blocks inside.
  • Add PR review checklists. "Did you add prevent_destroy?" Depends on human memory. Does not scale.
  • Wire up OPA or Sentinel policies. Can flag missing lifecycle blocks, but cannot add them to the code.

Each forked module is one more copy to re-fork and test on every upstream release, and forked versions drift apart across teams. With Operational Rules, the standards are defined once and applied to every module downloaded from the compliance.tf registry.

How rules work

  1. An org admin configures rules. On the Operational Rules page (or its API), rules go into the organization's Baseline, which applies to every module downloaded from the organization's host, or into a named ruleset that a module selects with ?ruleset=<name>. On a framework host, a module can also name rules for one download in its source line.
  2. A developer runs terraform init. The compliance.tf registry resolves the developer's org, looks up the org's rule configuration, and applies rules during module download.
  3. The module arrives with rules applied. Lifecycle blocks, provisioner removal, and instance restrictions are already in the HCL. The developer runs terraform plan and terraform apply normally.

Rules are applied server-side, at the same time as compliance controls. The downloaded module is standard Terraform HCL that you can read, diff, and audit like any other module. On your organization's own host, per-download overrides in the URL are refused with a 400 rather than ignored, because there the organization's configuration is the whole answer. Which query parameters each host accepts is on Rulesets in the console.

How rules relate to compliance controls

Compliance controlsOperational Rules
What it enforcesRegulatory requirementsOrganizational standards
Driven byFrameworks (SOC 2, PCI DSS, HIPAA, NIST...)Platform team decisions
ExamplesEncryption at rest, access logging, public access blockingprevent_destroy, ignore_changes, instance restrictions
Who configuresCompliance.tf (framework-defined)Org admins (org-defined)
Applied whenModule downloadModule download, after controls
Can be disabledPer module via ?disable= on a framework hostPer download via ?rules= on a framework host; on your organization's host only by changing the Baseline or a ruleset

Both layers apply during terraform init. Developers keep their usual workflow. When a rule and a control touch the same attribute, the changes merge additively. The first question below has the detail.

Frequently asked questions

Do operational rules affect compliance controls?

No. Operational Rules and compliance controls are independent layers. Controls are applied first (regulatory enforcement), rules are applied second (operational standards). A rule cannot override, weaken, or bypass a compliance control.

If a rule and a control affect the same resource attribute, the changes merge additively (for example, both adding to ignore_changes).

Rules live in a separate scope from controls: controls enforce encryption, logging, access blocking, and other regulatory requirements. Rules enforce lifecycle blocks, tagging behavior, provisioner removal, and instance restrictions.

Are rules part of my SOC 2, HIPAA, or PCI DSS compliance?

Rules are not compliance controls and should not be presented to auditors as regulatory enforcement. They are operational safety measures.

Several rules support operational practices that auditors view favorably:

  • Prevent destroy data and Prevent destroy encryption reduce the risk of accidental data loss, which supports data protection and availability objectives.
  • No provisioners removes a supply chain risk vector from module code, which supports change management and code integrity objectives.
  • Restrict instance types reports costly instance types written into module source, which supports cost governance.

If an auditor asks about these, describe them as operational safeguards that complement your compliance controls.

Can I disable rules?

Yes. On a framework host, a module can remove a rule for one download, or add one, in its HTTPS source line; Add your first rule shows both.

Free tier: you apply rules per request by naming them in your module source URL. Rules are not forced; you choose which to include.

Trial, paid and enterprise plans: org admins configure the organization's Baseline and rulesets on the Operational Rules page. On the framework and canonical hosts, individual developers can still override per request. On the organization's own host they cannot: a rule stops applying to a module only when it is taken out of the Baseline, or kept in a ruleset that module does not select. Org admins can also disable a rule for the entire organization. See Rulesets in the console.

Do rules work with OpenTofu?

Yes. Operational Rules modify the module source code (standard HCL) before it is downloaded. The resulting module works identically with Terraform and OpenTofu. There are no provider-specific or CLI-specific dependencies in the rule transformations.

All lifecycle meta-arguments (prevent_destroy, ignore_changes) and the absence of provisioner blocks are standard HCL features supported by both Terraform and OpenTofu.

What happens when rules change?

Rules are applied at download time (terraform init). If your org admin enables a new rule or changes the rule configuration, the change takes effect on the next terraform init -upgrade that downloads a fresh copy of the module.

Modules already downloaded and cached in .terraform/modules/ are not retroactively modified. To pick up new rules, run terraform init -upgrade. You can inspect the downloaded .tf files to see which rules were applied to a given module copy.

Can I write my own rules?

No. Every rule comes from the compliance.tf rule catalog; your organization chooses which ones apply and sets their parameters.

Does this work with Atlantis, Terragrunt, or HCP Terraform agents?

Yes. Rules are applied server-side during module download, so any tool that runs terraform init against the compliance.tf registry receives modules with rules applied; Terragrunt runs terraform init under the hood. Credential setup for each platform is on CI/CD integration.

How do I see exactly what was transformed?

Read the downloaded module. It is standard HCL in .terraform/modules/, and the lifecycle blocks, provisioner removals, and other transformations are in the code. To see a rule's diff before downloading, use Preview a rule or the Rules Playground.

A module compliance.tf builds for you also carries a compliancetf-manifest.json listing the rules the build received, each with an outcome saying what it did; a listed rule can have enforced nothing. The manifest records file paths, not resource addresses. How to read it, including which fields confirm that a change reached a module, is on How a module request resolves.

How do I know dev, staging, and prod got the same rules?

Compare the downloaded .tf files across environments. If the same module version was downloaded with the same rules in its source line, or from the same organization Baseline and ruleset, the resulting HCL will be identical. A diff or checksum of the downloaded module directories confirms consistency, and the manifest fields described on How a module request resolves identify the exact built variant.

What's my break-glass path when prevent_destroy blocks an intentional replacement?

Each rule page has a "Break-glass path" section for that rule, such as Prevent destroy data. On a framework host the path is a per-download override in the source line; on your organization's host it is an admin change to the Baseline or a ruleset, because URL overrides are refused there.

How do I leave compliance.tf without state churn?

Downloaded modules are standard Terraform HCL. The lifecycle blocks, tagging behavior, and provisioner changes are all written directly in the .tf files. To leave compliance.tf:

  1. Change the module source URL back to terraform-aws-modules/...
  2. Manually add the lifecycle blocks that your team needs (or don't; they are standard Terraform features you can add to any module)
  3. Run terraform init, which installs the module from its new source, and terraform plan

Because the lifecycle settings in compliance.tf modules are identical to what you would write by hand, there is no state migration, no resource recreation, and no proprietary format to unwind. If your existing state already has the values that rules enforce (for example prevent_destroy = true), the plan will show no changes.

Why should I trust your pipeline more than my own wrapper repo?

Here is what compliance.tf provides that a wrapper repo does not:

  • Transparency: The downloaded module is plain HCL. You can read every .tf file and see exactly what was transformed. A manifest file (compliancetf-manifest.json) records the rules requested, what each one actually did, and a variant fingerprint. A wrapper repo may add the same lifecycle blocks, but has no standard manifest format documenting what it changed.
  • Consistency: When the same rules are applied (named in the source line on a framework host, or from the organization's Baseline and rulesets), the same module version produces identical HCL. Wrapper repos depend on consistent builds and artifact promotion, which is possible but adds moving parts.
  • No maintenance burden: Wrapper repos require re-wrapping on every upstream module update. Compliance.tf applies rules to the latest upstream version automatically.
  • Inspectability: Open the downloaded .tf files and read them, or see the diff before downloading with Preview a rule.

If your wrapper repo is well maintained and working, you can keep it; rules give the same outcome without maintaining a fork.

Next steps

On this page

Ask AI about this

Help improve this page