compliance.tf

Ignore Secret Rotation

Adds ignore_changes for the database credential attribute on RDS instances and Aurora clusters. A rotated or regenerated password stops showing as a diff on every plan.

When to use this rule

Use this when: The database password comes from something that rotates or regenerates outside Terraform's control, and every plan shows a password diff.

Do not use this when: You rotate the password through Terraform and want the change applied, or the module hands rotation to AWS with manage_master_user_password, in which case Terraform never sets the attribute and there is nothing to ignore.


Why this rule exists

A regenerated random_password, a rotated Secrets Manager or Vault data source, or a variable supplied differently per runner gives Terraform a new value on every plan. Each plan proposes resetting the database password, and an apply that goes through resets it for real.

The fix is ignore_changes on the credential attribute, and a lifecycle block cannot be passed into an upstream module as a variable.

RepositoryIssueTitle
hashicorp/terraform#27360A method to override configuration and meta arguments within a module
hashicorp/terraform#24188Support for dynamic blocks and meta-arguments
hashicorp/terraform-provider-aws#19583Provider produced inconsistent final plan / an invalid new value for .tags_all

Limitations this rule answers

Per-module pages under Workarounds where this rule is the answer, each with the native workaround first and the diff the rule makes:


Affected resources

ResourceServiceWhy
aws_db_instanceAmazon RDSpassword, set from a value that changes between plans
aws_rds_clusterAmazon Auroramaster_password, set from a value that changes between plans

What this rule does

Adds a lifecycle { ignore_changes = [...] } block to each matching resource. Terraform and OpenTofu will ignore external changes to the listed attributes on subsequent plans.

Ignored attributes: password Adds a lifecycle { ignore_changes = [...] } block to each matching resource. Terraform and OpenTofu will ignore external changes to the listed attributes on subsequent plans.

Ignored attributes: master_password


Before and after

Before (upstream module):

resource "aws_db_instance" "this" {
  # ... resource configuration ...

  tags = var.tags
}

After (with Ignore Secret Rotation applied):

resource "aws_db_instance" "this" {
  # ... resource configuration ...

  tags = var.tags

  lifecycle {
    ignore_changes = [password]
  }
}

Before (upstream module):

resource "aws_db_instance" "this" {
  # ... resource configuration ...

  tags = var.tags
}

After (with Ignore Secret Rotation applied):

resource "aws_db_instance" "this" {
  # ... resource configuration ...

  tags = var.tags

  lifecycle {
    ignore_changes = [master_password]
  }
}

The only change is the rule transformation. All existing arguments, outputs, and module behavior remain identical.

Real-world scenario

A password came from a Secrets Manager data source that a rotation schedule rewrote weekly. Every plan proposed a password reset, and one Monday apply reset it for real.

The example above is illustrative. To see this rule run for real, open it in the Rules Playground β€” it applies lifecycle_ignore_secret_rotation to a reviewed upstream module that actually declares the resources this rule targets, and shows the diff the registry would serve. No account needed.


Known limits

  • Only password on aws_db_instance and master_password on aws_rds_cluster. Other engines and resources are not touched.
  • Does not rotate anything and does not manage the secret. It only stops Terraform from writing the attribute back.
  • Each attribute list is a parameter; an organization can set one to [] to contribute nothing for that resource type.
  • Only .tf and .tofu files are read. Modules written in JSON syntax (.tf.json, .tofu.json) are left untouched.
  • Only the module's own directory and its first-level modules/* submodules are processed. Modules that this module calls by source URL are separate downloads and are handled on their own request.

Default configuration

These are the values the rule ships with. They are not settable from a module source URL: ?rules= carries rule names only, so a per-request enable uses exactly the defaults below. Your organization sets them per rule, in its Baseline or in a ruleset, from the Operational Rules page; see Baseline rules and rulesets.

ParameterTypeDefaultDescription
db_instance_ignore_changeslist(string)["password"]Credential attributes on RDS instances. Override to [] to contribute nothing to the merged set
db_instance_resource_typeslist(string)["aws_db_instance"]Resource types whose credential attribute is named password
rds_cluster_ignore_changeslist(string)["master_password"]Credential attributes on Aurora clusters. Override to [] to contribute nothing to the merged set
rds_cluster_resource_typeslist(string)["aws_rds_cluster"]Resource types whose credential attribute is named master_password

The rule's definition

The HCL this rule is written in - its parameters, their shipped defaults, and the transformers it runs - is published at lifecycle_ignore_secret_rotation, alongside every other selectable rule.


How to enable

On a framework host, per request:

Add ?rules=lifecycle_ignore_secret_rotation to your HTTPS module source, using the id exactly as written.

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

A ?rules= list is either all bare names, which replace your organization's rules for that download, or all - prefixed names, which subtract from them. Mixing the two is refused with a 400 rather than silently treated as a replacement. To add this rule on top of your organization's rules instead, use ?add_rules=lifecycle_ignore_secret_rotation; a bare ?rules= list cannot be combined with it, because a bare list already replaced the set there was something to add to.

The + add prefix was removed. It reached the registry only when written %2B, and a literal + in a query string decodes to a space everywhere, so ?rules=+lifecycle_ignore_secret_rotation arrived as a bare name with a leading space β€” one step from silently replacing your organization's rules. Any +, in either spelling, is now a 400 naming ?add_rules=.

On your organization's host:

Add the rule to the organization's Baseline, which applies to every module served from the bare organization form <alias>.compliance.tf/<namespace>/<name>/<provider>, or to a named ruleset that one module selects with ?ruleset=<name> on the HTTPS form of that address. A project environment (<alias>.compliance.tf/<project>/<env>/<module>) serves the rules frozen in its bound snapshot instead: there the rule goes into the config draft and reaches the environment by promotion. On both organization forms ?rules= and ?add_rules= are refused with a 400 β€” including the subtractive - prefix β€” rather than dropped, so you cannot mistake an ignored override for an applied one. Change the configuration, not the URL. See Baseline rules and rulesets for the configuration flow, and registry resolution for how the address forms differ.


Break-glass path

On a framework host, add ?rules=-lifecycle_ignore_secret_rotation to the module source URL and run terraform init -upgrade to fetch a copy without this rule. The copy in .terraform/modules/ stays until the next upgrade, so remove the override when you are done. On your organization's host the parameter is refused with a 400 rather than ignored. The rule comes from the organization's configuration: a Baseline rule applies to every module served from the bare organization form, so an admin disables it for the duration of the operation, or keeps it out of the Baseline and in a ruleset that only the modules needing it select. On a project environment the posture is the bound snapshot and its waivers. See Baseline rules and rulesets.


Failure modes

ScenarioResult
Rule targets a module with no matching resource typesNo-op. Module is delivered unchanged and the manifest records not_applicable.
You change the password in Terraform on purposeThe change is ignored on plan. Rotate through the database or the secret store, or take the rule off that module for the operation.
The resource already carries an ignore_changes listThe list is kept and the attribute is merged in.

Terraform and OpenTofu compatible

This rule works with both Terraform (1.x+) and OpenTofu (1.6+). It reads ordinary HCL, and anything it changes stays ordinary HCL, so the module behaves the same under either tool.

Help us improve this page

Operational Rules are a new feature. We'd love your feedback on this rule page β€” what's useful, what's missing, what's confusing. Share feedback.

On this page

Ask AI about this

Help improve this page