Terraform aws_appautoscaling_target Deep Dive and Tagging Failure Analysis

Terraform's aws_appautoscaling_target resource registers a scalable target with AWS Application Auto Scaling, allowing services such as ECS services, DynamoDB tables, RDS clusters, and others to be managed by scaling policies. The resource maps directly to the AWS Application Auto Scaling API RegisterScalableTarget operation and is the prerequisite for attaching aws_appautoscaling_policy resources. Understanding its argument set, provider-level default_tags interaction, and known limitations is essential for reliable infrastructure as code.

Introduction

Application Auto Scaling in AWS requires an explicit registration step before scaling policies can be attached. The Terraform resource aws_appautoscaling_target performs that registration. It is typically used together with aws_appautoscaling_policy for step scaling or target tracking. Provider configuration with default_tags is a common pattern for enforcing organizational tagging standards, but a known bug with the AWS provider causes tag application to fail on creation when the scalable target already exists.

Core Arguments and Attribute Reference

The resource provides an Application AutoScaling ScalableTarget resource. To manage policies which get attached to the target, see the aws_appautoscaling_policy resource.

The following arguments are supported:

The documented arguments are:

  • max_capacity - Required. The max capacity of the scalable target.
  • min_capacity - Required. The min capacity of the scalable target.
  • resource_id - Required. The resource type and unique identifier string for the resource associated with the scaling policy. Documentation can be found in the ResourceId parameter at: AWS Application Auto Scaling API Reference.
  • role_arn - Optional. The ARN of the IAM role that allows Application AutoScaling to modify your scalable target on your behalf. The resource examples show it as Required in some documentation variants.
  • scalable_dimension - Required. The scalable dimension of the scalable target. Documentation can be found in the ScalableDimension parameter at: AWS Application Auto Scaling API Reference.
  • service_namespace - Required. The AWS service namespace of the scalable target. Documentation can be found in the ServiceNamespace parameter at: AWS Application Auto Scaling API Reference.

Attribute Reference:

  • arn - The ARN assigned by AWS to the scaling policy.
  • name - The scaling policy's name.

Example usages from documentation:

hcl resource "aws_appautoscaling_target" "dynamodb_table_read_target" { max_capacity = 100 min_capacity = 5 resource_id = "table/${aws_dynamodb_table.example.name}" role_arn = "${data.aws_iam_role.DynamoDBAutoscaleRole.arn}" scalable_dimension = "dynamodb:table:ReadCapacityUnits" service_namespace = "dynamodb" }

hcl resource "aws_appautoscaling_target" "dynamodb_index_read_target" { max_capacity = 100 min_capacity = 5 resource_id = "table/${aws_dynamodb_table.example.name}/index/${var.index_name}" role_arn = "${data.aws_iam_role.DynamoDBAutoscaleRole.arn}" scalable_dimension = "dynamodb:index:ReadCapacityUnits" service_namespace = "dynamodb" }

hcl resource "aws_appautoscaling_target" "ecs_target" { max_capacity = 4 min_capacity = 1 resource_id = "service/${aws_ecs_cluster.example.name}/${aws_ecs_service.example.name}" role_arn = "${var.ecs_iam_role}" scalable_dimension = "ecs:service:DesiredCount" service_namespace = "ecs" }

hcl resource "aws_appautoscaling_target" "replicas" { service_namespace = "rds" scalable_dimension = "rds:cluster:ReadReplicaCount" resource_id = "cluster:${aws_rds_cluster.example.id}" min_capacity = 1 max_capacity = 15 }

Documentation variants note defaults:

  • scalable_dimension defaults to ecs:service:DesiredCount since that is the only allowed value.
  • service_namespace defaults to ecs, because that is currently the only supported option.
  • max_capacity is Required.
  • min_capacity is Required.
  • role_arn is Required in some documentation variants.

Provider Default Tags Interaction

A common Terraform configuration uses provider-level default_tags:

hcl provider "aws" { region = var.aws_region default_tags { tags = { application = var.project stage = var.env squad = var.squad terraform = "true" repository = var.repository_name } } }

With this configuration, Terraform is expected to create resources and manage tags automatically by seeing the default_tags configuration on the provider. The aws_appautoscaling_target resource is declared as:

hcl resource "aws_appautoscaling_target" "service_scaling" { min_capacity = var.min_container_count max_capacity = var.max_container_count resource_id = "service/${aws_ecs_cluster.ecs_cluster.name}/${aws_ecs_service.ecs_service.name}" role_arn = aws_iam_role.autoscaling_role.arn scalable_dimension = "ecs:service:DesiredCount" service_namespace = "ecs" depends_on = [aws_ecs_service.ecs_service, aws_iam_role.autoscaling_role] }

The scaling policy is then attached:

hcl resource "aws_appautoscaling_policy" "service_scale_out" { name = "${var.project}-${var.env}-scale-out-policy" policy_type = "StepScaling" resource_id = aws_appautoscaling_target.service_scaling.resource_id scalable_dimension = aws_appautoscaling_target.service_scaling.scalable_dimension service_namespace = aws_appautoscaling_target.service_scaling.service_namespace step_scaling_policy_configuration { adjustment_type = "ChangeInCapacity" cooldown = 60 metric_aggregation_type = "Average" step_adjustment { scaling_adjustment = 1 metric_interval_lower_bound = 0 } } depends_on = [aws_appautoscaling_target.service_scaling] }

Known Bug: ValidationException on Tagging Existing Targets

A bug is documented for Terraform Core Version v1.4.6 with AWS Provider Version v4.67.0. Affected Resource is aws_appautoscaling_target.

Expected Behavior:
Terraform should create these resources and manage the tags automatically by seeing the default_tags configuration on the provider.

Actual Behavior:
When creating the these resources for the first time, the error occurs:

aws_appautoscaling_target.service_scaling: Creating... ╷ │ Error: creating Application AutoScaling Target (service/content-available-service-nonprod-ecs-cluster/content-available-service-nonprod-ecs-service): ValidationException: The scalable target that you tried to tag already exists │ │ To update tags on an existing scalable target, use the TagResource API. │ │ with aws_appautoscaling_target.service_scaling, │ on autoscaling.tf line 1, in resource "aws_appautoscaling_target" "service_scaling": │ 1: resource "aws_appautoscaling_target" "service_scaling" { │ ╵

The error message states: The scalable target that you tried to tag already exists. To update tags on an existing scalable target, use the TagResource API.

This indicates the provider attempts to create the scalable target with tags in a single call, but AWS returns a validation exception when the target already exists or when tags are applied during creation. The issue is reproducible with terraform apply.

The bug report confirms the user would like a fix implemented.

CloudFormation Equivalent

AWS CloudFormation provides AWS::ApplicationAutoScaling::ScalableTarget as the declarative equivalent.

The resource specifies a resource that Application Auto Scaling can scale, such as an AWS::DynamoDB::Table or AWS::ECS::Service resource.

Note: If the resource that you want Application Auto Scaling to scale is not yet created in your account, add a dependency on the resource when registering it as a scalable target using the DependsOn attribute.

Syntax:

JSON
json { "Type" : "AWS::ApplicationAutoScaling::ScalableTarget", "Properties" : { "MaxCapacity" : Integer , "MinCapacity" : Integer , "ResourceId" : String , "RoleARN" : String , "ScalableDimension" : String , "ScheduledActions" : [ ScheduledAction, ... ] , "ServiceNamespace" : String , "SuspendedState" : SuspendedState } }

YAML
yaml Type: AWS::ApplicationAutoScaling::ScalableTarget Properties: MaxCapacity: Integer MinCapacity: Integer ResourceId: String RoleARN: String ScalableDimension: String ScheduledActions: - ScheduledAction ServiceNamespace: String SuspendedState: SuspendedState

Properties:

  • MaxCapacity - The maximum value that you plan to scale out to
  • MinCapacity - The minimum value that you plan to scale in to
  • Additional properties include ResourceId, RoleARN, ScalableDimension, ServiceNamespace, ScheduledActions, and SuspendedState.

Specification Comparison

Terraform Argument CloudFormation Property Required Description
max_capacity MaxCapacity Yes The max capacity of the scalable target
min_capacity MinCapacity Yes The min capacity of the scalable target
resource_id ResourceId Yes The resource type and unique identifier string
role_arn RoleARN Optional / Required The ARN of the IAM role for Auto Scaling
scalable_dimension ScalableDimension Yes The scalable dimension of the target
service_namespace ServiceNamespace Yes The AWS service namespace of the target

Operational Considerations

  • The resource_id format is service specific. For ECS it is service/<cluster-name>/<service-name>. For DynamoDB table read capacity it is table/<table-name>.
  • scalable_dimension values are constrained per service namespace. For ECS the only allowed value is ecs:service:DesiredCount.
  • service_namespace currently defaults to ecs in some documentation variants, because that is currently the only supported option.
  • depends_on is often used to ensure the underlying ECS service, IAM role, or database resource exists before registration.
  • Tag management via provider default_tags does not currently work reliably for aws_appautoscaling_target due to the ValidationException bug. Workarounds involve removing default_tags for this resource or managing tags via separate aws_appautoscaling tag resources after creation.

Conclusion

The aws_appautoscaling_target resource is central to enabling Application Auto Scaling in Terraform for ECS, DynamoDB, RDS, and other supported services. Its argument set is minimal but strict: min_capacity, max_capacity, resource_id, role_arn, scalable_dimension, and service_namespace. The resource maps directly to AWS::ApplicationAutoScaling::ScalableTarget in CloudFormation.

The critical operational issue remains the provider-level default_tags interaction. With Terraform Core v1.4.6 and AWS Provider v4.67.0, creating an aws_appautoscaling_target with default tags results in ValidationException: The scalable target that you tried to tag already exists. The error instructs users to update tags via the TagResource API, which the provider does not correctly handle during initial creation. This prevents automatic tag inheritance and forces manual tagging workarounds.

Until the provider bug is fixed, teams should avoid relying on default_tags for auto scaling targets, explicitly manage tags after resource creation, or pin provider versions and monitor the upstream issue. The resource remains functionally correct for capacity registration and policy attachment, but tagging behavior makes it unsafe in environments enforcing mandatory tagging through provider defaults.

Sources

  1. HashiCorp Terraform Provider AWS Issue 31839
  2. W3CUB Terraform AWS AppAutoScaling Target Docs
  3. Koding Terraform AWS AppAutoScaling Target Docs
  4. AWS CloudFormation Application Auto Scaling ScalableTarget

Related Posts