compliance.tf

Auto Scaling: known Terraform limitations

Some things people ask the terraform-aws-modules/autoscaling/aws module for cannot be implemented by any module, in any registry. They are limits of Terraform and OpenTofu themselves. This page collects the recurring ones for this module, says plainly what causes each, gives the native workaround in full, and - where one exists - shows the Operational Rule that removes the need for a fork.

Read the native option first

Every problem below names the workaround you can apply today without compliance.tf. Several of them are the right answer on their own. The rule is an alternative to maintaining a fork, not a replacement for a control AWS already offers you. Where a rule exists, the source line at the end of this page applies it. To get started, register a free compliance.tf account and configure an access token. The Rules Playground shows the diff with no account.


Auto Scaling group desired_capacity reverts on every apply

A scaling policy, a scheduled action, or an operator scales the group. Terraform holds the desired_capacity from the configuration and scales it back on the next apply, which can remove capacity a live workload is using.

Why Terraform cannot fix this

Terraform's model is that it owns every attribute it can see. When a controller, an autoscaler, a scanner, or a deployment pipeline writes to one of those attributes, Terraform reads the new value as drift and plans to put its own value back. Both systems are behaving correctly; they simply disagree about who owns the field.

The only mechanism Terraform offers for splitting ownership is ignore_changes, and that is a lifecycle argument, which brings the literal-value restriction above with it. A module cannot accept the list of attributes to ignore as an input, so a module consumer has no way to declare the split.

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

The native workaround

The native fix is ignore_changes = [desired_capacity] on the Auto Scaling group, which is a lifecycle argument. Fork this module and add the lifecycle block to the resource yourself. That works, and it is the honest answer - it is what module maintainers do when they need it. The cost is ongoing rather than one-off: the fork has to be re-synced with every upstream release, and each sync needs a review to confirm the block still lands on the resource it was meant for. A wrapper module does not avoid this, because the lifecycle block still has to sit inside the resource block, which is inside the module you did not write.

Leaving desired_capacity unset entirely also works: AWS then keeps the current value and Terraform has nothing to revert to.

The rule that answers it

lifecycle_ignore_scaling_changes adds the block for you, server-side, while the module is being downloaded. What arrives in .terraform/modules/ is ordinary HCL with this change already in it:

 resource "aws_autoscaling_group" "this" {
   # ... the module's own configuration, unchanged ...
+
+  lifecycle {
+    ignore_changes = [desired_capacity]
+  }
 }

Nothing else about the module changes: same inputs, same outputs, same version. The full definition is published at lifecycle_ignore_scaling_changes.


Using the maintained alternative

compliance.tf serves this module from a registry that applies the rules above during terraform init. The change is the source line plus the rules you want; the inputs and outputs are the upstream module's. The version goes into the URL as ?version= (an exact release; without it the registry serves the latest, so pin it); delete the version argument, which Terraform accepts only on registry-protocol sources. Several rules go in ?add_rules= separated by commas.

module "autoscaling" {
  source = "https://registry.compliance.tf/terraform-aws-modules/autoscaling/aws?version=x.y.z&add_rules=lifecycle_ignore_scaling_changes"

  # ... the same inputs you pass today; the version is in the URL above ...
}

To get started, register a free compliance.tf account and configure an access token; the token never goes in the source line or in git.

On registry.compliance.tf, or on a framework host, you name the rules you want in ?add_rules=, on top of whatever Baseline your organization has Enforced; on an organization host that organization's configuration decides. A module compliance.tf builds for you carries a compliancetf-manifest.json naming every rule the build received, each with an outcome recording what it actually did, so the change is auditable rather than implicit.

Before changing a source line, open Auto Scaling in the Rules Playground with these rules selected: it shows the diff at the version it pins for Auto Scaling, which need not be the one you put in ?version=, with no account.

The preview reads the module root, and only the root. A rule whose resource lives in a submodule shows no diff there even though the download applies it, and a module that publishes nothing but submodules cannot be previewed at all - the Playground says so rather than showing an empty result. Neither changes what the source line below does; both change what the Playground can show you first. The Playground takes its list as ?rules= because it previews rules on their own rather than against your Baseline; your source line above keeps ?add_rules=, which adds to that Baseline instead of replacing it.


On this page

Ask AI about this

Help improve this page