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.
This article covers the full Terraform workflow for provisioning an Auto Scaling group with AWS, from launch template and launch configuration definitions to scaling policies, load balancer attachments, lifecycle hooks, instance refresh, and module-based patterns. The focus is on authoritative configuration details, state drift avoidance, and production-ready patterns for managing desiredcapacity, minsize, max_size, health checks, and target group associations without unwanted Terraform interventions.
Core Concepts and Terraform Drift Behavior
AWS Auto Scaling Groups (ASGs) 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.
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.
Terraform's interaction with ASGs is constrained by the dynamic nature of the resource. Because scaling actions are performed by the Auto Scaling service, not by Terraform, the provider must be careful not to overwrite or conflict with runtime changes. The standard pattern is to let Terraform provision the ASG and its supporting resources, then allow AWS to manage instance count.
The tutorial you will use Terraform to provision and manage an Auto Scaling group and learn how Terraform configuration supports the dynamic aspects of the resource. You will launch an ASG with traffic managed by a load balancer and define a scaling policy to automatically modify the number of instances running in the group. You will learn how to use lifecycle arguments to avoid unwanted scaling of your ASG.
This tutorial assumes that you are familiar with the standard Terraform workflow.
Launch Template Versus Launch Configuration
A launch configuration block specifies a name prefix to use for all versions of this launch configuration.
Modern configurations prefer launch templates over launch configurations because launch templates support versioning, more instance metadata, and mixed instance policies. The example below defines a launch template and then uses this in the autoscaling group resource block.
```
provider "aws" {
region = "us-west-2"
}
resource "awslaunchtemplate" "template" {
nameprefix = "test"
imageid = "ami-1a2b3c"
instancetype = "t2.micro"
securitygroups = ["sg-12345678"]
}
resource "awsautoscalinggroup" "autoscale" {
name = "test-autoscaling-group"
availabilityzones = ["us-west-2"]
desiredcapacity = 3
maxsize = 6
minsize = 3
healthchecktype = "EC2"
terminationpolicies = ["OldestInstance"]
vpczone_identifier = ["subnet-12345678"]
launchtemplate {
id = awslaunch_template.template.id
version = "$Latest"
}
}
```
The launch configuration block specifies a name prefix to use for all versions of this launch configuration.
```
provider "aws" {
region = "ap-south-1"
}
resource "awslaunchconfiguration" "terraformautoscale" {
nameprefix = "example-config-"
imageid = "ami-05a5bb48beb785bf1"
instancetype = "t2.micro"
}
resource "awsautoscalinggroup" "terraformautoscale" {
name = "terraform-asg"
launchconfiguration = awslaunchconfiguration.terraformautoscale.name
minsize = 2
maxsize = 5
desiredcapacity = 2
vpczoneidentifier = ["subnet-0c5af440c5754fee0", "subnet-0efc610622152af6"]
}
```
Comparison of Launch Methods
| Attribute | Launch Template | Launch Configuration |
|---|---|---|
| Versioning | Supported | Not supported |
| Instance metadata options | Supported | Limited |
| Mixed instances policy | Supported | Not supported |
| Typical use | Production ASGs | Legacy examples |
Autoscaling Group Resource Attributes
The autoscaling group resource is the central construct. Key attributes include name, availabilityzones, desiredcapacity, maxsize, minsize, healthchecktype, terminationpolicies, vpczoneidentifier, and launchtemplate or launch_configuration.
A minimal ASG definition with lifecycle protection looks like this:
resource "aws_autoscaling_group" "terramino" {
min_size = 1
max_size = 3
desired_capacity = 1
launch_configuration = aws_launch_configuration.terramino.name
vpc_zone_identifier = module.vpc.public_subnets
}
Lifecycle arguments are critical to avoid drift. When you 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.
To prevent Terraform from scaling your instances when it changes other aspects of your configuration, use a lifecycle argument to ignore changes to the desired capacity and target groups.
lifecycle {
ignore_changes = [desired_capacity, target_group_arns]
}
Now run terraform apply to set the lifecycle rule on the resource.
Load Balancer Integration and Target Group Attachments
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.
In this blog, you will learn how to deploy a Terraform autoscaling group with an application load balancer using step-by-step guides.
We are going to build the following in this guide.
- AWS Autoscaling group spanning three subnets.
- IAM role attached to Autoscaling instances to access other AWS services
- Application Load Balancer attached to the Autoscaling group
Throughout this article, we will be using the following short names.
- ALB - Application load balancer
- ASG - Autoscaling Group
Prerequisites to follow this guide you need to have the following.
- The latest Terraform binary is installed and configured in your system.
- AWS CLI is installed and configured with a valid AWS account with permission to deploy the autoscaling group and application load balancer.
- If you are using an ec2 instance to run Terraform, ensure you attach an IAM role with permission to create ASG and ALB.
Setup Architecture & Overview
Here is the high-level architecture of the setup we are going to create.
Here is the high-level overview of the AWS resources and components created by this setup.
- IAM role with required policies and the role is attached to an IAM instance profile which will be then attached to every instance that is part of the autoscaling group.
- The auto-scaling group manages a specified number of instances and uses the launch template
Determine the scaling policies you want to apply to the Auto Scaling group.
How to create an AWS Auto Scaling Group in Terraform
- Define a launch configuration block and autoscaling group block
The example below defines a launch template and then uses this in the autoscaling group resource block (you should use these instead of launch configurations).
Scaling Policies and Capacity Management
ASGs let you manage the number of running instances manually or dynamically. Define a scaling policy to automatically modify the number of instances running in the group.
Common parameters for capacity management are:
- desired_capacity: the target number of instances
- min_size: lower bound for automatic scaling
- max_size: upper bound for automatic scaling
- healthchecktype: EC2 or ELB
- health_check Grace period
Scaling policies define the conditions under which the group scales up or down, such as CPU utilization, network traffic, or other custom metrics.
Terraform module which creates Auto Scaling resources on AWS.
- Autoscaling group with launch template - either created by the module or utilizing an existing launch template
- Autoscaling group utilizing mixed instances policy
- Ability to configure autoscaling groups to set instance refresh configuration and add lifecycle hooks
- Ability to create an autoscaling group that respects desired_capacity or one that ignores to allow for scaling without conflicting Terraform diffs - IAM role and instance profile creation
Module-Based Autoscaling with Advanced Features
The terraform-aws-modules/autoscaling module provides production-ready defaults and advanced configuration.
Example usage:
```
module "asg" {
source = "terraform-aws-modules/autoscaling/aws"
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"]
}
}
```
Instance refresh enables safe rolling updates of instances in an ASG. The module supports configuration of instance refresh with strategy Rolling and preferences including checkpointdelay, checkpointpercentages, instancewarmup, minhealthypercentage, maxhealthy_percentage, and triggers.
Lifecycle hooks allow integration with external systems during instance launch and termination. The module supports ability to configure autoscaling groups to set instance refresh configuration and add lifecycle hooks.
The module also supports ability to create an autoscaling group that respects desired_capacity or one that ignores to allow for scaling without conflicting Terraform diffs.
Security Groups, IAM Roles, and Networking
Determine the scaling policies you want to apply to the Auto Scaling group.
Read more about managing security groups through Terraform.
A typical ASG requires:
- VPC subnets via vpczoneidentifier
- Security groups via launch template
- IAM role attached to instances to access other AWS services
The auto-scaling group manages a specified number of instances and uses the launch template.
Common Operational Patterns
- Use launch_template block with id and version = "$Latest" for immutable updates
- Set termination_policies to control which instances are removed first
- Use healthchecktype = "EC2" for basic health or "ELB" when behind a load balancer
- Apply lifecycle { ignorechanges = [desiredcapacity, targetgrouparns] } when ASG is managed by external autoscaling policies
- Use waitforcapacity_timeout = 0 in modules to avoid Terraform timeouts during slow scale out
Conclusion
Terraform provides a robust way to provision and manage AWS Auto Scaling groups while respecting the dynamic nature of instance scaling. Launch templates are preferred over launch configurations for new deployments because they support versioning and mixed instance policies. Lifecycle arguments are essential to prevent Terraform from reverting desired_capacity changes or target group attachments managed by AWS Auto Scaling.
Load balancer integration requires careful handling of target group associations to avoid mutually exclusive configuration errors. Using awsautoscalingattachment alongside lifecycle ignore_changes is a proven pattern for keeping Terraform state consistent with runtime scaling actions.
The terraform-aws-modules/autoscaling module abstracts complex patterns such as instance refresh, lifecycle hooks, mixed instances policy, and IAM role creation. It provides options to respect or ignore desired_capacity, enabling safe co-existence with external scaling controllers.
Production ASG designs should define explicit minsize, maxsize, desiredcapacity, healthchecktype, vpczone_identifier, and scaling policies based on application demand. With proper lifecycle management and module usage, Terraform can declaratively define the ASG shape while allowing AWS to dynamically manage instance count without state drift.