compliance.tf

Baseline Rules and Rulesets

  • An organization's operational rules live in two groups. The Baseline applies to every module served from the organization's own host. A ruleset is a named group that one module opts into by adding ?ruleset=<name> to its source.
  • ?ruleset= selects a group the organization already published. It cannot add a parameter, change a value, or remove a rule; a selected ruleset is applied on top of the Baseline, never instead of it.
  • The live rules — Baseline and rulesets — apply only while the organization's rules state is Enforced. Disabled and Preview keep the configuration without applying it. Rules frozen in the organization's baseline snapshot apply regardless.
  • A project environment is different: it serves the rules frozen in its bound snapshot, and refuses ?ruleset=.
  • The module's manifest records which rules came from a ruleset, by name and content hash.

Where an organization's rules come from

Three address forms, three answers. Module request resolution covers the whole path; this table is the rules column of it.

Address formRules applied?ruleset=?rules=
https://<alias>.compliance.tf/<namespace>/<name>/<provider> — the organization's bare formThe Baseline, plus the rules frozen in the organization's baseline snapshot, plus the ruleset the request names, if anyHonouredRefused, 400
<alias>.compliance.tf/<project>/<env>/<module> — a project environmentThe rules list frozen in the snapshot the environment is bound to, nothing elseRefused, 400Refused, 400
soc2.compliance.tf, registry.compliance.tf — framework and canonical hostsThe names in ?rules= with their catalog defaults, merged with the Baseline of the token holder's organization when that organization's rules state is EnforcedNot used hereHonoured
Which rules a download receives Flowchart: a request on an organization's bare host receives the Baseline, the rules frozen in the baseline snapshot and any ruleset the source selects; a project environment receives only the rules of its bound snapshot; a framework host receives the rule names in ?rules= with their catalog defaults. All three produce a built module with a manifest inside. ?RULESET= BINDING ?RULES= Organization hostbare form: /<ns>/<name>/<provider> Project environment/<project>/<env>/<module> Framework hostsoc2.compliance.tf Baseline + rulesetlive store + baseline snapshot Bound snapshotfrozen rules only Named rulescatalog defaults Built modulemanifest inside LEGENDAddress formRule sourceSelected per module callOutput

Two details of the first row matter when you author rules:

  • Rules from two stores meet on the bare form. The Operational Rules page edits a live store: the Baseline and the rulesets. The organization's baseline snapshot — a published config, see Configs and snapshots — may name rules too. The registry serves the union. When both name the same rule with different parameters, the snapshot's parameters win, because a snapshot was published under review and a live row can be edited by anyone with the admin role. The collision is logged rather than resolved silently, so a live edit to a rule the snapshot also names does not reach the download.
  • No baseline, no module. An organization whose baseline snapshot was never set — the pointer described under the organization's own baseline posture — gets a 404 ORG_BASELINE_NOT_CONFIGURED on the bare form rather than a module with no posture.

Credentials for the bare form

The bare form is an HTTPS source, so Terraform authenticates it from .netrc rather than from a TF_TOKEN_* variable — the same mechanism the HTTPS URL format uses on a framework host, with the organization's alias as the machine:

machine acme.compliance.tf
    login anything
    password ctf_EXAMPLE_TOKEN

The token must belong to a member of that organization, or be an organization token bound to it. Any other credential is refused with a 403, whatever the path.

The Baseline

The Baseline is every rule instance in the live store that carries no ruleset name. Open Operational Rules in the organization's dashboard (app.compliance.tf/orgs/<alias>/operational-rules): the Baseline is the first card, marked applies to every module, and it cannot be renamed or deleted.

Each rule in it is an instance of a catalog rule with its own parameters — the tag keys to ignore, the regions to allow, the instance types to deny. A parameter is validated against the catalog when you save it: an unknown parameter or a value of the wrong type is refused, and a parameter with no default that you leave out is absent rather than null. Which rules exist and what each one enforces is the rule catalog's job; this page is about where an instance lives.

The rules state gates all of it. The toggle at the top of the page has three positions: Disabled, Preview and Enforced. Only Enforced sends the live rules to a build. In Disabled and Preview the Baseline and every ruleset are stored and shown but not applied, and a module served in either state carries no live rule. The rules frozen in the baseline snapshot are outside the toggle: they are part of a published posture and apply while the pointer names that snapshot. A change of state reaches a workspace on its next fresh download — terraform init -upgrade where the module is already cached — like any rule change.

Named rulesets

A ruleset is a name attached to rule instances, not a separate object with its own life. Giving a rule a ruleset name moves it out of the Baseline; clearing the name moves it back. That has consequences worth knowing before you plan around them:

PropertyBehaviour
Creating oneAdd a rule under a new name, or move an existing rule into it. The name must match ^[a-z][a-z0-9-]&#123;1,63&#125;$.
MembershipToday the live store holds one instance of each catalog rule per organization, so a rule is in the Baseline or in exactly one ruleset. It cannot be in two rulesets, and a rule in a ruleset is not in the Baseline. A disabled rule is skipped wherever it lives. (The baseline snapshot is a separate, frozen copy; see above.)
RenamingRenames every member at once. A name that already exists is refused with a 409; nothing is merged silently.
DeletingUngroups: the members return to the Baseline with their parameters intact. Nothing is removed from the store.
Registry visibilityThe registry knows a ruleset by the enabled rules that carry its name. A ruleset whose rules are all disabled, or one you have just created and not yet filled, is unknown to the registry and refused as such.
Versioning, approvalNone. A ruleset is live-edited; a change is visible on the next fresh download. There is no immutable version, no approval step and no content pin a source string can name. The manifest's content hash (below) tells you which content a given build saw.

A rule that moves from the Baseline into a ruleset stops applying to every other module. If the intent is "every module, plus one extra rule for these three", the extra rule goes in the ruleset and the shared rules stay in the Baseline.

Selecting a ruleset per module call

A module opts into a ruleset from its source, on the HTTPS form of the bare organization address:

module "logs_bucket" {
  source = "https://acme.compliance.tf/terraform-aws-modules/s3-bucket/aws?version=5.0.0&ruleset=ignore-scanner-tags"
}

The build receives the Baseline, whatever the baseline snapshot froze, and every enabled rule named ignore-scanner-tags. The parameters are the ones the organization saved; the URL contributes a name and nothing else. Without a prefix, ?rules= on a framework host replaces the defaults for that download; ?ruleset= never replaces anything.

RequestAnswer
Name matches an enabled rule in the organizationApplied, on top of the Baseline
Name is not a ruleset of this organization, or all its rules are disabled400 ORG_HOST_RULESET_UNKNOWN
Name does not match ^[a-z][a-z0-9-]&#123;1,63&#125;$400 ORG_HOST_RULESET_INVALID
?ruleset= on a project environment (<alias>.compliance.tf/<project>/<env>/<module>)400 ORG_HOST_RULESET_UNSUPPORTED_ON_PROJECT_PATH — that path serves its snapshot, and attributing a ruleset it cannot apply would be a false claim
?ruleset= together with ?rules=, ?enable=, ?disable= or ?framework=400 ORG_HOST_POSTURE_OVERRIDE_REJECTED — the four posture parameters stay refused on an organization host, with or without a ruleset

Three consequences of the mechanism:

  • Per module call means per distinct source string. The registry sees the URL, never the module label. Two blocks with byte-identical sources are one download and one variant; to give one bucket a ruleset and another none, their source strings must differ — which is what you want in a code review anyway.
  • Editing a ruleset changes the artifact, not the version. The served module version does not encode the ruleset, but the variant identity includes a hash of the ruleset's content, so a changed ruleset is a new build rather than a stale cache hit. A fresh workspace picks it up on terraform init; one that already resolved the module keeps its copy until terraform init -upgrade. Editing the Baseline changes the artifact the same way.
  • Every rule in the ruleset is applied to every module that selects it. There is no per-resource targeting: a rule scoped to aws_s3_bucket acts on every bucket resource in the module, and a module with no matching resource records the rule as not applicable.

What the manifest records

The compliancetf-manifest.json written into the module lists every rule the build received under operational_rules[]. A rule that arrived through a ruleset carries one extra field:

{
  "rule": "lifecycle_ignore_tag_keys",
  "outcome": "enforced",
  "ruleset": { "name": "ignore-scanner-tags", "content_hash": "3f9c2a71b0e4d8c5" }
}

name is the ruleset the source selected. content_hash is a 16-character truncated SHA-256 over the ruleset's rules and parameters as the build saw them, so two modules built from the same ruleset content carry the same hash and an edited ruleset produces a different one. Baseline rules carry no ruleset field at all; its absence means "part of the organization's baseline posture", not "unknown". The manifest does not tell a live Baseline rule from one frozen in the baseline snapshot: both are unstamped.

Read outcome before reading presence, as on every rule: a listed rule can have enforced nothing, because its parameters were empty or because the module had no resource it targets. How to read the rest of the manifest is on Operational rules.

Why this one parameter is accepted where the others are refused

An organization host refuses ?rules=, ?enable=, ?disable= and ?framework= with a 400, and Module request resolution explains why: any of them lets whoever edits a source string author or subtract posture, and production posture must not be editable from a module block.

?ruleset= is different in kind, not in degree. It carries a name, and the name resolves on the server to rules and parameters an organization admin saved. It cannot introduce a value the organization did not configure, and it cannot remove anything: the Baseline is always applied, and a ruleset only adds to it. The source string selects among postures the organization published; it never writes one. That is the whole of the exception, and it is why the refused set did not shrink to make room for it.

Who may do what

ActionRequired
Read the Baseline and the rulesetsMembership in the organization
Add, edit, move, enable or disable a rule; rename or ungroup a ruleset; change the rules stateThe admin role, on a trial, paid or enterprise plan. On the free plan these writes are refused with a 403 and an upgrade message — see Plans and entitlements
Download a module from the organization's hostA registry token that belongs to a member, or an organization token bound to the organization — see Registry tokens

Worked example: ignore a scanner's tag on one bucket

A vulnerability scanner writes a scanner-last-seen tag on the buckets it inspects, and Terraform plans to remove it on every run. The organization wants that key ignored on the log buckets the scanner touches, not on every bucket.

  1. On the Operational Rules page, create a ruleset ignore-scanner-tags and add Ignore Selected Tag Keys to it with tag_keys = ["scanner-last-seen"]. Leave resource_types at its default, aws_s3_bucket. Confirm the rules state is Enforced.

  2. Point the affected module at the ruleset:

    module "alb_logs" {
      source = "https://acme.compliance.tf/terraform-aws-modules/s3-bucket/aws?version=5.0.0&ruleset=ignore-scanner-tags"
    }

    Every other s3-bucket call keeps its plain source and receives the Baseline (and the baseline snapshot's rules) only.

  3. Run terraform init -upgrade. In .terraform/modules/alb_logs/main.tf the bucket resource now carries ignore_changes = [tags["scanner-last-seen"]], and compliancetf-manifest.json lists lifecycle_ignore_tag_keys with outcome: "enforced" and ruleset.name: "ignore-scanner-tags".

This rule cannot be selected with ?rules= on any host: a name containing a dot is refused with a 400 on every host, and the rule's default tag list is empty anyway. A ruleset is the only way to apply it to some modules and not others.

On this page

Ask AI about this

Help improve this page