Sign in
Menu
Start free trial

AWS Auto Scaling Group (ASG) Terraform module

Terraform module which creates Auto Scaling resources on AWS.

SWUbanner

Available Features

  • 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

Usage

module "asg" {
  source  = "terraform-aws-modules/autoscaling/aws"

  # Autoscaling group
  name = "example-asg"

  min_size                  = 0
  max_size                  = 1
  desired_capacity          = 1
  wait_for_capacity_timeout = 0
  health_check_type         = "EC2"
  vpc_zone_identifier       = ["subnet-1235678", "subnet-87654321"]

  initial_lifecycle_hooks = [
    {
      name                  = "ExampleStartupLifeCycleHook"
      default_result        = "CONTINUE"
      heartbeat_timeout     = 60
      lifecycle_transition  = "autoscaling:EC2_INSTANCE_LAUNCHING"
      notification_metadata = jsonencode({ "hello" = "world" })
    },
    {
      name                  = "ExampleTerminationLifeCycleHook"
      default_result        = "CONTINUE"
      heartbeat_timeout     = 180
      lifecycle_transition  = "autoscaling:EC2_INSTANCE_TERMINATING"
      notification_metadata = jsonencode({ "goodbye" = "world" })
    }
  ]

  instance_refresh = {
    strategy = "Rolling"
    preferences = {
      checkpoint_delay       = 600
      checkpoint_percentages = [35, 70, 100]
      instance_warmup        = 300
      min_healthy_percentage = 50
      max_healthy_percentage = 100
    }
    triggers = ["tag"]
  }

  # Launch template
  launch_template_name        = "example-asg"
  launch_template_description = "Launch template example"
  update_default_version      = true

  image_id          = "ami-ebd02392"
  instance_type     = "t3.micro"
  ebs_optimized     = true
  enable_monitoring = true

  # IAM role & instance profile
  create_iam_instance_profile = true
  iam_role_name               = "example-asg"
  iam_role_path               = "/ec2/"
  iam_role_description        = "IAM role example"
  iam_role_tags = {
    CustomIamRole = "Yes"
  }
  iam_role_policies = {
    AmazonSSMManagedInstanceCore = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
  }

  block_device_mappings = [
    {
      # Root volume
      device_name = "/dev/xvda"
      no_device   = 0
      ebs = {
        delete_on_termination = true
        encrypted             = true
        volume_size           = 20
        volume_type           = "gp2"
      }
    }, {
      device_name = "/dev/sda1"
      no_device   = 1
      ebs = {
        delete_on_termination = true
        encrypted             = true
        volume_size           = 30
        volume_type           = "gp2"
      }
    }
  ]

  capacity_reservation_specification = {
    capacity_reservation_preference = "open"
  }

  cpu_options = {
    core_count       = 1
    threads_per_core = 1
  }

  credit_specification = {
    cpu_credits = "standard"
  }

  instance_market_options = {
    market_type = "spot"
    spot_options = {
      block_duration_minutes = 60
    }
  }

  # This will ensure imdsv2 is enabled, required, and a single hop which is aws security
  # best practices
  # See https://docs.aws.amazon.com/securityhub/latest/userguide/autoscaling-controls.html#autoscaling-4
  metadata_options = {
    http_endpoint               = "enabled"
    http_tokens                 = "required"
    http_put_response_hop_limit = 1
  }

  network_interfaces = [
    {
      delete_on_termination = true
      description           = "eth0"
      device_index          = 0
      security_groups       = ["sg-12345678"]
    },
    {
      delete_on_termination = true
      description           = "eth1"
      device_index          = 1
      security_groups       = ["sg-12345678"]
    }
  ]

  placement = {
    availability_zone = "us-west-1b"
  }

  tag_specifications = [
    {
      resource_type = "instance"
      tags          = { WhatAmI = "Instance" }
    },
    {
      resource_type = "volume"
      tags          = { WhatAmI = "Volume" }
    },
    {
      resource_type = "spot-instances-request"
      tags          = { WhatAmI = "SpotInstanceRequest" }
    }
  ]

  tags = {
    Environment = "dev"
    Project     = "megasecret"
  }
}

Conditional creation

The following combinations are supported to conditionally create resources and/or use externally created resources within the module:

Note: the default behavior of the module is to create an autoscaling group and launch template.

  • Disable resource creation (no resources created):
  create                 = false
  create_launch_template = false
  • Create only a launch template:
  create = false
  • Create an autoscaling group using an externally created launch template:
  create_launch_template = false
  launch_template        = aws_launch_template.my_launch_template.name
  • Create an autoscaling group with a mixed instance policy:
  use_mixed_instances_policy = true
  • Create the autoscaling policies:
  scaling_policies = {
    my-policy = {
      policy_type               = "TargetTrackingScaling"
      target_tracking_configuration = {
        predefined_metric_specification = {
          predefined_metric_type = "ASGAverageCPUUtilization"
          resource_label         = "MyLabel"
        }
        target_value = 50.0
      }
    }
  }

Known limitations (Terraform/OpenTofu, not this module)

A few requests come up again and again and cannot be implemented by this module, or by any module: Terraform requires lifecycle arguments to be literal values inside the resource block. hashicorp/terraform#18367 has been open since 2018, #22544 since 2019, and opentofu/opentofu#1329 is the same request for OpenTofu.

  • Auto Scaling group desired_capacity reverts on every apply - Native options: leave desired_capacity unset, or fork and add ignore_changes = [desired_capacity].

Compliance.tf serves this module with these rules applied at download time, on top of whatever your organization already has enabled there. Inputs and outputs do not change; the source line does. Drop the version argument and pin the release you use by adding &version= and that release number to the URL. To get started, register a free compliance.tf account and configure an access token:

source = "https://registry.compliance.tf/terraform-aws-modules/autoscaling/aws?add_rules=lifecycle_ignore_scaling_changes"

The full workaround for each item above, and the exact diff each rule makes, are in the compliance.tf docs for this module. To preview a diff without an account, open this module in the Rules Playground.

Disclosure: written by this module's maintainer, who also builds compliance.tf.

Examples

  • Complete - Creates several variations of resources for autoscaling groups and launch templates.

Notes

  • A refresh will not start if launch_template_version is set to $Latest when using an external launch template. To trigger the refresh when the external launch template is changed, set this to latest_version of that aws_launch_template resource.

Authors

Module is maintained by Anton Babenko with help from these awesome contributors.

License

Apache 2 Licensed. See LICENSE for full details.

Additional information for users from Russia and Belarus