Introduction
Terraform modules for AWS autoscaling exist at the intersection of declarative infrastructure code and dynamically managed runtime capacity. The terraform-aws-modules/terraform-aws-autoscaling repository provides a Terraform module which creates Auto Scaling resources on AWS. The module covers an autoscaling group with launch template, either created by the module or utilizing an existing launch template. The module also covers an autoscaling group utilizing mixed instances policy. The module provides ability to configure autoscaling groups to set instance refresh configuration and add lifecycle hooks. The module provides ability to create an autoscaling group that respects desired_capacity or one that ignores to allow for scaling without conflicting Terraform diffs. The module includes IAM role and instance profile creation.
The compliance.tf distribution of the module is described as Terraform AWS Autoscaling. The description states Auto Scaling groups with launch templates, instance refresh, health checks, scaling policies, mixed instance options, IAM instance profiles, and security group based network controls. Controls enforced are checked at terraform plan time.
The HashiCorp tutorial material explains that AWS Auto Scaling groups let you easily scale and manage a collection of EC2 instances that run the same instance configuration. You can then manage the number of running instances manually or dynamically, allowing you to lower operating costs. Since ASGs are dynamic, Terraform does not manage the underlying instances directly because every scaling action would introduce state drift. You can use Terraform lifecycle arguments to avoid drift or accidental changes.
The Spacelift article context states that AWS Auto Scaling Groups let you quickly scale and manage a collection of EC2 instances that run the same instance configuration. ASGs automatically scale the number of instances in response to changes in demand or other scaling policies. They ensure that the desired number of instances are always running, helping to maintain application availability and handle fluctuating workloads. Scaling policies define the conditions under which the group scales up or down, such as CPU utilization, network traffic, or other custom metrics.
These overlapping descriptions create a dense operational picture where module capabilities, compliance controls, Terraform state behavior, and hands-on configuration patterns must be understood together. The following sections expand each reference fact through direct fact statement, impact layer, and contextual layer.
Module Capabilities and Resource Coverage
The terraform-aws-modules/terraform-aws-autoscaling module creates Auto Scaling resources on AWS.
The module supports an autoscaling group with launch template. The launch template can be either created by the module or utilizing an existing launch template. The ability to choose between creation and reuse changes how teams manage versioning and drift. Creating the launch template inside the module centralizes instance type, image, security groups, and IAM profile definition. Reusing an existing launch template decouples template lifecycle from autoscaling group lifecycle and allows separate approval gates for AMI changes.
The module supports an autoscaling group utilizing mixed instances policy. Mixed instances policy enables cost optimization and availability across instance types. The impact is reduced single-instance-type risk and price volatility exposure. The contextual connection is that mixed instances policy works in conjunction with launch template and instance refresh to roll capacity safely.
The module provides ability to configure autoscaling groups to set instance refresh configuration and add lifecycle hooks. Instance refresh enables controlled replacement of instances. Lifecycle hooks allow integration with external systems during launch and termination.
The module provides ability to create an autoscaling group that respects desired_capacity or one that ignores to allow for scaling without conflicting Terraform diffs. This directly addresses state drift concerns where autoscaling activities performed outside Terraform would otherwise generate perpetual diffs.
The module includes IAM role and instance profile creation. The IAM role and instance profile creation ensures that instances launched by the group have least-privilege access to AWS services without manual role provisioning.
Launch Template Integration and Mixed Instances Policy
The module documentation references an example module block.
```hcl
module "asg" {
source = "terraform-aws-modules/autoscaling/aws"
Autoscaling group
name = "example-asg"
minsize = 0
maxsize = 1
desiredcapacity = 1
waitforcapacitytimeout = 0
healthchecktype = "EC2"
vpczoneidentifier = ["subnet-1235678", "subnet-87654321"]
initiallifecyclehooks = [
{
name = "ExampleStartupLifeCycleHook"
defaultresult = "CONTINUE"
heartbeattimeout = 60
lifecycletransition = "autoscaling:EC2INSTANCELAUNCHING"
notificationmetadata = jsonencode({ "hello" = "world" })
},
{
name = "ExampleTerminationLifeCycleHook"
defaultresult = "CONTINUE"
heartbeattimeout = 180
lifecycletransition = "autoscaling:EC2INSTANCETERMINATING"
notificationmetadata = jsonencode({ "goodbye" = "world" })
}
]
instancerefresh = {
strategy = "Rolling"
preferences = {
checkpointdelay = 600
checkpointpercentages = [35, 70, 100]
instancewarmup = 300
minhealthypercentage = 50
maxhealthypercentage = 100
}
triggers = ["tag"]
}
Launch
```
The name is example-asg. The minsize is 0. The maxsize is 1. The desiredcapacity is 1. The waitforcapacitytimeout is 0. The healthchecktype is EC2. The vpczoneidentifier is ["subnet-1235678", "subnet-87654321"].
The initiallifecyclehooks list contains two hooks. The first hook name is ExampleStartupLifeCycleHook. The defaultresult is CONTINUE. The heartbeattimeout is 60. The lifecycletransition is autoscaling:EC2INSTANCELAUNCHING. The notificationmetadata is jsonencode({ "hello" = "world" }). The second hook name is ExampleTerminationLifeCycleHook. The defaultresult is CONTINUE. The heartbeattimeout is 180. The lifecycletransition is autoscaling:EC2INSTANCETERMINATING. The notificationmetadata is jsonencode({ "goodbye" = "world" }).
The instancerefresh block uses strategy Rolling. Preferences include checkpointdelay 600, checkpointpercentages [35, 70, 100], instancewarmup 300, minhealthypercentage 50, maxhealthypercentage 100. Triggers is ["tag"].
The impact of these values is that the autoscaling group can be scaled to zero, allowing cost savings during idle periods. The healthchecktype EC2 means instance health is determined by EC2 status checks rather than ELB. The vpczoneidentifier pins the group to two specific subnets, controlling AZ placement.
The lifecycle hooks provide a CONTINUE default result, meaning the hook will not block the transition unless an external system intervenes. The heartbeat_timeout values differ between launch and termination, reflecting that startup validation may need less time than graceful shutdown.
The instance refresh rolling strategy with checkpoints at 35, 70, and 100 percent allows operators to pause the refresh if error rates rise. The instancewarmup of 300 seconds gives applications time to become healthy before health checks are considered. The minhealthypercentage 50 and maxhealthy_percentage 100 bound the number of instances that can be replaced concurrently.
Instance Refresh Configuration and Lifecycle Hooks
Instance refresh configuration is exposed by the module. The strategy is Rolling. Preferences control the speed and safety of the refresh.
The checkpoint_delay is 600. This means 600 seconds elapse between checkpoints. The impact is that operators have time to observe metrics before proceeding.
The checkpoint_percentages are [35, 70, 100]. These percentages define points at which the refresh pauses for validation.
The instance_warmup is 300. New instances are given 300 seconds to warm up before being considered healthy.
The minhealthypercentage is 50. At least 50 percent of the desired capacity must remain healthy during refresh.
The maxhealthypercentage is 100. No more than 100 percent of capacity can be healthy, which is the default ceiling.
Triggers is ["tag"]. The refresh triggers on tag changes.
Lifecycle hooks are configured via initiallifecyclehooks. The module allows hooks for autoscaling:EC2INSTANCELAUNCHING and autoscaling:EC2INSTANCETERMINATING. The hooks carry notification_metadata encoded as JSON.
Contextually, instance refresh and lifecycle hooks operate together. A lifecycle hook can perform a registration step before an instance enters service, while instance refresh orchestrates the replacement of the fleet under the hook constraints.
Desired Capacity Handling and Drift Prevention
The module provides ability to create an autoscaling group that respects desired_capacity or one that ignores to allow for scaling without conflicting Terraform diffs.
In the HashiCorp tutorial, the awsautoscalinggroup resource is defined with minsize = 1, maxsize = 3, desiredcapacity = 1, launchconfiguration = awslaunchconfiguration.terramino.name, vpczoneidentifier = module.vpc.public_subnets.
The lifecycle block is added to ignore changes.
hcl
lifecycle {
ignore_changes = [desired_capacity, target_group_arns]
}
The impact of ignorechanges for desiredcapacity is that manual scaling actions performed via AWS console, CLI, or autoscaling policies do not cause Terraform to revert the capacity. Without this, Terraform would detect a difference between the state file and the actual ASG and attempt to enforce the declared desired_capacity on every apply.
The impact of ignorechanges for targetgroup_arns is that associating or dissociating a target group outside Terraform does not create drift. The tutorial notes that Terraform now respects dynamic scaling operations and does not disassociate your ASG from the load balancer target group.
The tutorial states that you can associate a target group with an ASG both through a standalone resource as done in the current configuration, or through an inline argument to the awsautoscalinggroup resource. The two are mutually exclusive, so if you use the awsautoscalingattachment resource as done in this configuration, you must ignore changes to the attribute of the ASG resource itself.
The state list output from the tutorial shows resources Terraform is tracking.
bash
$ terraform state list
data.aws_ami.amazon_linux
data.aws_availability_zones.available
aws_autoscaling_attachment.terramino
aws_autoscaling_group.terramino
aws_launch_configuration.terramino
aws_lb.terramino
aws_lb_listener.terramino
aws_lb_target_group.terramino
aws_security_group.terramino_instance
aws_security_group.terramino_lb
module.vpc.aws_internet_gateway.this[0]
module.vpc.aws_route.public_internet_gateway[0]
module.vpc.aws_route_table.public[0]
module.vpc.aws_route_table_association.public[0]
module.vpc.aws_route_table_association.public[1]
module.vpc.aws_route_table_association.public[2]
module.vpc.aws_subnet.public[0]
module.vpc.aws_subnet.public[1]
module.vpc.aws_subnet.public[2]
module.vpc.aws_vpc.this[0]
Notice that Terraform does not list your ASG's EC2 instances in the state's resources. This is because Terraform is not aware of the member instances of the group, only the capacity.
The impact is that operators must understand that Terraform state does not contain individual EC2 instances created by the ASG. Scaling actions create and destroy instances without Terraform tracking them, which is why drift avoidance patterns are required.
Compliance Controls and Migration Path
The compliance.tf distribution provides Terraform AWS Autoscaling with controls enforced at terraform plan time.
Controls enforced are checked at terraform plan time.
Quick start migration from upstream is described. Already using terraform-aws-modules? Change only the source URL. Same arguments. Same outputs. Controls are checked at terraform plan. See the Migration Guide for step-by-step instructions.
Reversibility is provided. No lock-in. Switch back by reverting the source URL. Run terraform init -upgrade. Terraform state is unchanged — same resource addresses, same provider, no compliance.tf-specific resources. Controls you already applied remain in AWS.
Mapped compliance frameworks are provided.
Table: Framework coverage
| Control | PCI DSS v4.0 | SOC 2 |
|---|---|---|
| EC2 launch templates should use Instance Metadata Service Version 2 (IMDSv2) | ○ | ○ |
| EC2 launch templates should not assign public IPs to network interfaces | ● | ● |
● enforced by default · ○ not activated by this endpoint
The impact of plan-time controls is that non-compliant configurations fail before apply, reducing risk of deploying insecure launch templates.
The migration path preserves arguments and outputs, so existing Terraform code continues to work. Reversibility ensures teams can move back to the upstream module without state manipulation.
Example Configuration Patterns
The Spacelift article shows how to create an AWS Auto Scaling Group in Terraform.
The example defines a launch template and then uses this in the autoscaling group resource block.
hcl
provider "aws" {
region = "us-west-2"
}
resource "aws_launch_template" "template" {
name_prefix = "test"
image_id = "ami-1a2b3c"
instance_type = "t2.micro"
security_groups = ["sg-12345678"]
}
resource "aws_autoscaling_group" "autoscale" {
name = "test-autoscaling-group"
availability_zones = ["us-west-2"]
desired_capacity = 3
max_size = 6
min_size = 3
health_check_type = "EC2"
termination_policies = ["OldestInstance"]
vpc_zone_identifier = ["subnet-12345678"]
launch_template {
id = aws_launch_template.template.id
version = "$Latest"
}
}
The launch configuration block specifies a name prefix to use for all versions of this launch configuration.
The availabilityzones is ["us-west-2"]. The desiredcapacity is 3. The maxsize is 6. The minsize is 3. The healthchecktype is EC2. The terminationpolicies is ["OldestInstance"]. The vpczone_identifier is ["subnet-12345678"].
The launchtemplate block references id = awslaunch_template.template.id and version = "$Latest".
The impact of using $Latest is that any new version of the launch template is automatically used by the ASG on the next scaling event or instance refresh. This enables rapid rollout of AMI or security group changes.
The minsize 3 and maxsize 6 define a scaling window. The desired_capacity 3 establishes baseline capacity.
Terraform State Awareness and ASG Dynamics
The HashiCorp tutorial emphasizes that AWS Auto Scaling groups let you easily scale and manage a collection of EC2 instances that run the same instance configuration. You can then manage the number of running instances manually or dynamically, allowing you to lower operating costs. Since ASGs are dynamic, Terraform does not manage the underlying instances directly because every scaling action would introduce state drift. You can use Terraform lifecycle arguments to avoid drift or accidental changes.
The tutorial states you can scale the number of instances in your ASG manually as you did earlier in this tutorial.
The contextual layer connects this to the module's ignore desiredcapacity option and the lifecycle ignorechanges pattern. Both mechanisms solve the same problem from different angles: module-level abstraction versus resource-level lifecycle.
Scaling Policies and Operational Considerations
AWS Auto Scaling Groups automatically scale the number of instances in response to changes in demand or other scaling policies. They ensure that the desired number of instances are always running, helping to maintain application availability and handle fluctuating workloads.
Scaling policies define the conditions under which the group scales up or down, such as CPU utilization, network traffic, or other custom metrics.
To utilize an auto-scaling group, you need to have a clear understanding of your application's scaling requirements to be able to define appropriate policies.
The module supports scaling policies via separate resources or module outputs. The healthchecktype EC2 versus ELB determines how unhealthy instances are replaced.
Conclusion
The terraform-aws-modules/terraform-aws-autoscaling module, the compliance.tf distribution, the HashiCorp tutorial, and the Spacelift configuration examples together form a comprehensive view of Terraform managed autoscaling on AWS. The module provides autoscaling groups with launch templates, mixed instances policy, instance refresh, lifecycle hooks, IAM role and instance profile creation, and options to respect or ignore desiredcapacity. The compliance distribution adds plan-time controls for IMDSv2 and public IP assignment with reversible migration from the upstream module. The tutorial material demonstrates that Terraform does not track individual EC2 instances created by an ASG, which requires lifecycle ignorechanges for desiredcapacity and targetgroup_arns to prevent perpetual diffs. Example configurations show launch template usage with version $Latest, VPC zone identifiers, health check types, and termination policies. Instance refresh rolling strategies with checkpoints, warmup periods, and healthy percentage bounds provide safe fleet replacement. Lifecycle hooks for launching and terminating instances enable integration with external systems. The combination of these patterns allows teams to deploy autoscaling capacity declaratively while allowing dynamic scaling operations to occur without state conflict.