Set EKS Node Group Desired Size
Lets Terraform change a terraform-aws-eks managed node group's desired, min and max size after create, by calling aws eks update-nodegroup-config from terraform_data when the variables change.
When to use this rule
Use this when: You run managed node groups from terraform-aws-eks and need to resize them from code: pre-scaling before a traffic event, raising the floor for a batch window, or scaling down at night.
Do not use this when: The machine that runs terraform apply has no AWS CLI or no credentials for the node group's account (HCP Terraform remote runs, for example), or you want Terraform to keep detecting changes made outside it to min, max or desired size.
Why this rule exists
terraform-aws-eks ignores scaling_config[0].desired_size on purpose, so Cluster Autoscaler or Karpenter can own the node count. The other side of that choice: once a node group exists, changing desired_size plans no change, and raising min_size above the live desired size fails with InvalidParameterException: Minimum capacity 2 can't be greater than desired size 1.
The module FAQ points to eks-desired-size-hack, which runs aws eks update-nodegroup-config from a provisioner. This rule serves the same idea inside the module: it also ignores min_size and max_size on the node group resource, and adds two terraform_data resources that send the new sizes in one call when the variables change. Limits run first and keep the autoscaler's current desired size while it is still in range; the desired size is then sent on its own.
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
| Resource | Service | Why |
|---|---|---|
aws_eks_node_group | Amazon EKS | scaling_config on managed node groups from terraform-aws-eks modules/eks-managed-node-group |
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: scaling_config[0].min_size, scaling_config[0].max_size
Before and after
Before (upstream module):
resource "aws_eks_node_group" "this" {
# ... resource configuration ...
tags = var.tags
}After (with Set EKS Node Group Desired Size applied):
resource "aws_eks_node_group" "this" {
# ... resource configuration ...
tags = var.tags
lifecycle {
ignore_changes = [scaling_config[0].min_size, scaling_config[0].max_size]
}
}The only change is the rule transformation. All existing arguments, outputs, and module behavior remain identical.
Real-world scenario
A team raised min_size from 2 to 4 before a launch. The apply failed with Minimum capacity 4 can't be greater than desired size 2, and the node group had to be resized in the console before Terraform would converge.
Known limits
- Managed node groups only. Self-managed node groups (
desired_capacityon the Auto Scaling group) are out of scope. - Applies only to modules shaped like terraform-aws-eks
modules/eks-managed-node-group:aws_eks_node_group.thisplus thecreate,min_size,max_sizeanddesired_sizevariables. Anything else getsnot_applicable. - After enabling, Terraform no longer detects or reverts changes made outside it to min, max or desired size. It pushes a value only when the variable changes.
- Cannot be combined with
provisioner_remove_blocks, which would strip the updater; the registry refuses the pair by name. - Only
.tfand.tofufiles 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.
The rule's definition
The HCL this rule is written in - its parameters, their shipped defaults, and the transformers it runs - is published at eks_node_group_set_desired_size, alongside every other selectable rule.
How to enable
On a framework host, per request:
Add ?rules=eks_node_group_set_desired_size 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=eks_node_group_set_desired_size"
}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=eks_node_group_set_desired_size; 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=+eks_node_group_set_desired_size 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=-eks_node_group_set_desired_size 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
| Scenario | Result |
|---|---|
| The runner has no AWS CLI | Apply fails with the AWS CLI is required on the machine that runs terraform apply. Nothing changes on the node group. |
| Credentials are for another AWS account | Apply fails before any update, naming the credential's account and the node group ARN. |
| First apply after enabling on an existing node group | The declared desired_size is pushed once, overwriting an autoscaler's current value. Set desired_size to the live value before enabling. |
| Another update is running on the node group | The update is retried for up to 30 minutes, then the apply fails and the next apply tries again. |
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.