Sign in
Menu
Sign up
Docs
Operational rules

Add your first rule

For platform engineers who want an operational standard, such as prevent_destroy on data stores, in modules they did not write. When you finish, one module downloads with the rule applied, and you have checked the change in the module source and in its manifest. Typically under 5 minutes.

Operational Rules apply your organization's operational standards to modules at download time, without forks or wrapper modules. They are separate from compliance controls: controls run first, rules run second. Rules overview explains the model.

Before you start

Step 1: Pick a rule

Open the Rule catalog and pick a rule. Each rule page lists what the rule changes, which resources it affects, before-and-after HCL, and whether your organization needs to configure it first. This guide uses Prevent destroy data, lifecycle_prevent_destroy_data, on the S3 bucket module.

To see a rule's diff before you change any source line, run it in the Rules Playground. No account, and no terraform init.

Step 2: Add the rule to your module

The rule's location depends on the host in your module source.

On a framework host

On a framework host like soc2.compliance.tf, add the rule id to the HTTPS module source with ?add_rules=. It applies on top of any Baseline your organization has Enforced:

module "s3_bucket" {
  source = "https://soc2.compliance.tf/terraform-aws-modules/s3-bucket/aws?version=5.0.0&add_rules=lifecycle_prevent_destroy_data"
}

Several rules go in one ?add_rules=, separated by commas. Parameters never travel in a URL, so each rule runs with its shipped defaults, and a rule whose defaults are empty does nothing from here.

On your organization's host

On your organization's host, such as bobthecorp.compliance.tf, rules come from the organization's configuration, and posture parameters in the URL, ?add_rules= and ?rules= among them, are refused with a 400. An org admin adds the rule on the Operational Rules page of the dashboard at app.compliance.tf, either to the Baseline, which applies to every module from that host, or to a named ruleset, which applies to the modules that select it with ?ruleset=. An organization host accepts ?ruleset= because it names a group the organization itself published:

module "logs_bucket" {
  source = "https://bobthecorp.compliance.tf/terraform-aws-modules/s3-bucket/aws?version=5.0.0&ruleset=protect-data"
}

That page needs a signed-in dashboard session with the org admin role, on a trial, paid or enterprise plan; the ctf_ registry token authenticates module downloads only. Parameters, such as the tag keys to ignore or the regions to allow, are set per rule on that page.

Every query parameter each host accepts, and what each refuses, is on Rulesets in the console.

Step 3: Download the module

Run terraform init -upgrade. If you changed the source line, plain terraform init installs the new source; -upgrade also forces a fresh download when the source is unchanged, as after a Baseline or ruleset change:

terraform init -upgrade

Expected output:

Initializing modules...
Downloading https://soc2.compliance.tf/terraform-aws-modules/s3-bucket/aws?version=5.0.0&add_rules=lifecycle_prevent_destroy_data for s3_bucket...
- s3_bucket in .terraform/modules/s3_bucket

Initializing provider plugins...

Terraform has been successfully initialized!

Check the result

Look for the change in the downloaded module source:

grep -B1 -A2 "prevent_destroy" .terraform/modules/s3_bucket/main.tf

Expected output:

  lifecycle {
    prevent_destroy = true
  }

The lifecycle block was not in the upstream terraform-aws-modules version.

Then read compliancetf-manifest.json in .terraform/modules/s3_bucket/. A module compliance.tf builds for you carries it, recording the rules that were requested, the file paths that changed, and a variant fingerprint. Read each rule's outcome rather than its presence: enforced means the rule made its change, and a listed rule can still have enforced nothing. Each rule page has a "How to check it worked" section for that rule.

Troubleshooting

terraform init succeeds but the module has no lifecycle block

On a framework host, check that the module source includes ?add_rules= with the rule id. On your organization's host, check the Operational Rules page: the rule must be in the Baseline, or in the ruleset the module selects, and the rules state must be Enforced. If neither is set, and your organization has no rules frozen in its baseline snapshot, no rules are applied.

The module may also be cached from an earlier download. Run terraform init -upgrade to force a fresh one.

A rule and a compliance control seem to affect the same resource

Controls run first, rules run second. If both affect the same attribute, changes are merged additively (for example, both adding entries to ignore_changes). If you see unexpected behavior, adjust your rule configuration to avoid overlap with the control.

I want to exclude one rule for one module

On a framework host, ?rules=-<id> removes a rule for that download:

module "s3_bucket" {
  source = "https://soc2.compliance.tf/terraform-aws-modules/s3-bucket/aws?version=5.0.0&rules=-lifecycle_prevent_destroy_data"
}

On your organization's host that parameter is refused with a 400. A Baseline rule applies to every module, so move it into a ruleset that only the modules needing it select, or disable it for the whole organization.

I get a 401 or 403 on the Operational Rules page or its API

The org rules API uses your signed-in dashboard session, not the registry access token. Sign in at app.compliance.tf and retry. A 403 means your account lacks the org admin role, or your organization is not on a trial, paid or enterprise plan.

Next steps

On this page

Ask AI about this

Help improve this page