Sign in
Menu
Sign up
Docs
Operational rulesWorkarounds

EKS

Some things people ask the terraform-aws-modules/eks/aws module for cannot be implemented by any module, in any registry: they are limits of Terraform and OpenTofu themselves. This page is for engineers who hit one of them. For each it says what causes it, 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; several are the right answer on their own.

Changing desired_size on an EKS node group does nothing, and raising min_size fails

The module sets ignore_changes = [scaling_config[0].desired_size] on aws_eks_node_group (and ignore_changes = [desired_capacity] on the self-managed node group's Auto Scaling group), so Cluster Autoscaler or Karpenter can own the size without Terraform reverting it. The other side of that choice: once the node group exists, changing desired_size plans no change at all, and raising min_size above the live desired size fails at the AWS API with InvalidParameterException: Minimum capacity 2 can't be greater than desired size 1. The module cannot make the ignore optional, because ignore_changes only takes literal values. The module FAQ explains the choice: https://github.com/terraform-aws-modules/terraform-aws-eks/blob/master/docs/faq.md#why-are-there-no-changes-when-a-node-groups-desired_size-is-modified

Why Terraform cannot fix this. lifecycle is a meta-argument block, and Terraform evaluates it before it evaluates the rest of the configuration. Its arguments therefore cannot reference a variable, a local, or anything else that is computed. That is the whole reason no module can expose prevent_destroy, ignore_changes, or create_before_destroy as an input: there is no expression a module author could put there that Terraform would accept.

The request was first filed in 2015 (#3116, closed in 2023 without a change). The module-specific asks, #18367 and #22544, have been open since 2018 and 2019, and OpenTofu carries the same request. Until one of them ships a way to set a meta-argument from outside the resource block, every module in every registry has the same limitation.

RepositoryIssueTitle
hashicorp/terraform#22544"Variables may not be used here" for prevent_destroy
hashicorp/terraform#18367Feature request: support prevent_destroy for modules
hashicorp/terraform#24746Ability to use locals or wildcards in ignore_changes lifecycle block
hashicorp/terraform#24188Support for dynamic blocks and meta-arguments
hashicorp/terraform#27360A method to override configuration and meta arguments within a module
opentofu/opentofu#1329Support variables in lifecycle blocks

The native workaround. desired_size cannot simply be left out: the provider requires it in scaling_config. Change the size outside Terraform instead - the EKS console, aws eks update-nodegroup-config --scaling-config minSize=...,maxSize=...,desiredSize=..., or your autoscaler. Send the new minimum and desired size in one call when you raise both.

To keep the change in code, run that command from a terraform_data or null_resource provisioner in your own configuration, as https://github.com/bryantbiggs/eks-desired-size-hack shows. It needs the AWS CLI and credentials on the machine that runs terraform apply.

The rule that answers it. eks_node_group_set_desired_size 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, and nothing else about the module changes: same inputs, same outputs, same version.

 resource "aws_eks_node_group" "this" {
   # ... the module's own configuration, unchanged ...
+
+  lifecycle {
+    ignore_changes = [scaling_config[0].min_size, scaling_config[0].max_size]
+  }
 }

Use the rule

This source line applies the rules above during terraform init. The inputs and outputs stay the upstream module's.

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

  # ... the same inputs you pass today; the version is in the URL above ...
}
  • Pin the version in the URL. ?version= takes an exact release; without it the registry serves the latest. Delete the version argument, which Terraform accepts only on registry-protocol sources. Several rules go in ?add_rules=, separated by commas.
  • Keep the token out of the source line. Register a free compliance.tf account and configure an access token; it never goes in the source line or in git.
  • Preview in the Playground, within its limits. The Rules Playground shows the diff with no account, at the version it pins for EKS, which need not be yours. It reads the module root only: 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. It takes the list as ?rules= because it previews rules on their own rather than against your Baseline.

On registry.compliance.tf, or on a framework host, ?add_rules= adds to 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 did.

On this page

Ask AI about this

Help improve this page