Terraform
Configure default tags for AWS resources
AWS recommends that you define a robust and consistent tagging strategy to enable better auditing, cost, and access control for your AWS resources. The AWS Terraform provider v3.38.0+ allows you to add default tags to all resources that the provider creates, making it easier to implement a consistent tagging strategy for all of the AWS resources you manage with Terraform.
In this tutorial, you will configure a set of default tags for your AWS resources. Then, you will override those tags for a specific resource. You will also learn how to use the default tags configuration to manage Auto Scaling group tags.
Prerequisites
You can complete this tutorial using the same workflow with either Terraform Community Edition or HCP Terraform. HCP Terraform is a platform that you can use to manage and execute your Terraform projects. It includes features like remote state and execution, structured plan output, workspace resource summaries, and more.
This tutorial assumes that you are familiar with the Terraform and HCP Terraform workflows. If you are new to Terraform, complete Get Started tutorials first. If you are new to HCP Terraform, complete the HCP Terraform Get Started tutorials first.
For this tutorial, you will need:
- Terraform v1.1+ installed locally.
- an HCP Terraform account and organization.
- HCP Terraform locally authenticated.
- an AWS account.
- the AWS CLI.
- an HCP Terraform variable set configured with your AWS credentials.
jq
installed.
Clone example repository
Clone the example repository for this tutorial, which contains configuration for an EC2 instance and an Auto Scaling group with default tags.
$ git clone https://github.com/hashicorp/learn-terraform-aws-default-tags.git
Change into the repository directory.
$ cd learn-terraform-aws-default-tags
Review example configuration
Open main.tf
to review the example configuration.
The default_tags
block in the AWS provider defines Environment
and
Service
tags.
main.tf
provider "aws" {
profile = "default"
region = "us-east-2"
default_tags {
tags = {
Environment = "Test"
Service = "Example"
HashiCorp-Learn = "aws-default-tags"
}
}
}
The default_tags
block applies tags to all resources managed by this
provider, except for the Auto Scaling groups (ASG).
Create infrastructure
Set the TF_CLOUD_ORGANIZATION
environment variable to your HCP Terraform
organization name. This will configure your HCP Terraform integration.
$ export TF_CLOUD_ORGANIZATION=
Initialize your configuration. Terraform will automatically create the learn-terraform-aws-default-tags
workspace in your HCP Terraform organization.
$ terraform init
Initializing HCP Terraform...
Initializing provider plugins...
- Reusing previous version of hashicorp/aws from the dependency lock file
- Installing hashicorp/aws v4.4.0...
- Installed hashicorp/aws v4.4.0 (signed by HashiCorp)
HCP Terraform has been successfully initialized!
You may now begin working with HCP Terraform. Try running "terraform plan" to
see any changes that are required for your infrastructure.
If you ever set or change modules or Terraform Settings, run "terraform init"
again to reinitialize your working directory.
Note
This tutorial assumes that you are using a tutorial-specific HCP Terraform organization with a global variable set of your AWS credentials. Review the Create a Credential Variable Set for detailed guidance. If you are using a scoped variable set, assign it to your new workspace now.
Apply your configuration to deploy an EC2 instance and Auto Scaling group.
Respond yes
to the prompt to confirm the operation.
$ terraform apply
##...
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
##...
Plan: 3 to add, 0 to change, 0 to destroy.
Changes to Outputs:
+ asg_id = (known after apply)
+ instance_id = (known after apply)
Do you want to perform these actions in workspace "learn-terraform-aws-default-tags"?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
##...
Apply complete! Resources: 3 added, 0 changed, 0 destroyed.
Outputs:
asg_id = "terraform-20210719192917609900000003"
instance_id = "i-06a3a837c7b181eb9"
Tip
This tutorial shows the output for Terraform commands run in HCP Terraform. If you are following the Terraform Community Edition workflow, the output may differ slightly but the results will be the same.
If you use HCP Terraform to provision your resources, your workspace now displays the list of all of the resources it manages.
Now, verify the EC2 instance tags using the AWS CLI.
$ aws ec2 describe-tags --region us-east-2 --filters "Name=resource-id,Values=$(terraform output instance_id)"
{
"Tags": [
{
"Key": "Environment",
"ResourceId": "i-029afcc3300e49d5a",
"ResourceType": "instance",
"Value": "Test"
},
{
"Key": "HashiCorp-Learn",
"ResourceId": "i-029afcc3300e49d5a",
"ResourceType": "instance",
"Value": "aws-default-tags"
},
{
"Key": "Service",
"ResourceId": "i-029afcc3300e49d5a",
"ResourceType": "instance",
"Value": "Example"
}
]
}
Then, check the tags on the Auto Scaling group. As expected, Terraform did not apply the default tags to this resource.
$ aws autoscaling describe-tags --region us-east-2 --filters "Name=auto-scaling-group,Values=$(terraform output asg_id)"
{
"Tags": []
}
You can also verify the tags on your resources by inspecting your EC2 instances and Auto Scaling groups in the AWS console.
Propagate default tags to Auto Scaling group
An Auto Scaling group is a collection of EC2 instances that use the same configuration. You can define the range of instances in an Auto Scaling group and the desired count, and the service will ensure that that number of instances is running at any given time. If an instance is terminated, the Auto Scaling group will launch another in its place using the launch configuration at the time.
AWS Auto Scaling Groups (ASGs) dynamically create and destroy EC2 instances as defined in the ASG's configuration. Because these EC2 instances are created and destroyed by AWS, Terraform does not manage them, and is not directly aware of them. As a result, the AWS provider cannot apply your default tags to the EC2 instances managed by your ASG. You can, however, use a data source and dynamic blocks to apply the default tags set on the provider to EC2 instances managed by your ASG.
Add the following data source to your main.tf
file to access the default tags
configured for the workspace's provider.
main.tf
data "aws_default_tags" "current" {}
Then, add the following block to the aws_autoscaling_group.example
configuration to dynamically generate a tag block for each item in the
aws_default_tags
data source.
main.tf
resource "aws_autoscaling_group" "example" {
availability_zones = data.aws_availability_zones.available.names
desired_capacity = 1
max_size = 1
min_size = 1
launch_template {
id = aws_launch_template.example.id
version = "$Latest"
}
dynamic "tag" {
for_each = data.aws_default_tags.current.tags
content {
key = tag.key
value = tag.value
propagate_at_launch = true
}
}
}
Now apply your configuration again. Respond yes
to the prompt to add the tags to your Auto Scaling Group's configuration.
$ terraform apply
##...
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
~ update in-place
Terraform will perform the following actions:
# aws_autoscaling_group.example will be updated in-place
~ resource "aws_autoscaling_group" "example" {
id = "terraform-20210716142031230900000003"
name = "terraform-20210716142031230900000003"
# (23 unchanged attributes hidden)
+ tag {
+ key = "Environment"
+ propagate_at_launch = true
+ value = "Test"
}
+ tag {
+ key = "HashiCorp-Learn"
+ propagate_at_launch = true
+ value = "aws-default-tags"
}
+ tag {
+ key = "Service"
+ propagate_at_launch = true
+ value = "Example"
}
# (1 unchanged block hidden)
}
Plan: 0 to add, 1 to change, 0 to destroy.
Do you want to perform these actions in workspace "learn-terraform-aws-default-tags"?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
aws_autoscaling_group.example: Modifying... [id=terraform-20210716142031230900000003]
aws_autoscaling_group.example: Modifications complete after 2s [id=terraform-20210716142031230900000003]
Apply complete! Resources: 0 added, 1 changed, 0 destroyed.
Outputs:
asg_id = "terraform-20210719192917609900000003"
instance_id = "i-06a3a837c7b181eb9"
Use the AWS CLI to confirm that the Auto Scaling group now has the default tags.
$ aws autoscaling describe-tags --region us-east-2 --filters "Name=auto-scaling-group,Values=$(terraform output asg_id)"
{
"Tags": [
{
"ResourceId": "terraform-20210720164457433400000003",
"ResourceType": "auto-scaling-group",
"Key": "Environment",
"Value": "Test",
"PropagateAtLaunch": true
},
{
"ResourceId": "terraform-20210720164457433400000003",
"ResourceType": "auto-scaling-group",
"Key": "Service",
"Value": "Example",
"PropagateAtLaunch": true
}
]
}
After the previous apply, the running EC2 instance in the Auto Scaling group does not have the desired default tags because the instance only has the tags configured for the Auto Scaling group at the time of the instance's launch.
Check the Auto Scaling group EC2 instance tags using the AWS CLI.
$ aws ec2 describe-instances --region us-east-2 --filter Name=tag:aws:autoscaling:groupName,Values=$(terraform output asg_id) | jq -r '.Reservations[].Instances[].Tags'
[
{
"Key": "aws:ec2launchtemplate:id",
"Value": "lt-0f4d78298300bdcf6"
},
{
"Key": "aws:ec2launchtemplate:version",
"Value": "1"
},
{
"Key": "aws:autoscaling:groupName",
"Value": "terraform-20210720164457433400000003"
}
]
The tags include the default ASG tags but not the default tags from your provider configuration.
Use the -replace
option for terraform apply
to reprovision the Auto Scaling
group and launch a new instance with the appropriate tags.
$ terraform apply -replace aws_autoscaling_group.example
##...
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
-/+ destroy and then create replacement
Terraform will perform the following actions:
# aws_autoscaling_group.example will be replaced, as requested
-/+ resource "aws_autoscaling_group" "example" {
##...
Plan: 1 to add, 0 to change, 1 to destroy.
Changes to Outputs:
~ asg_id = "terraform-20210720164457433400000003" -> (known after apply)
Do you want to perform these actions in workspace "learn-terraform-aws-default-tags"?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
##...
Apply complete! Resources: 1 added, 0 changed, 1 destroyed.
Outputs:
asg_id = "terraform-20210720190627748400000001"
instance_id = "i-04a84802a4bf1f0e9"
Confirm that the new EC2 instance managed by the ASG has the default tags.
$ aws ec2 describe-instances --region us-east-2 --filter Name=tag:aws:autoscaling:groupName,Values=$(terraform output asg_id) | jq -r '.Reservations[].Instances[].Tags'
[
{
"Key": "aws:ec2launchtemplate:id",
"Value": "lt-0315d238026484bf7"
},
{
"Key": "aws:autoscaling:groupName",
"Value": "terraform-20220308175102572300000001"
},
{
"Key": "Service",
"Value": "Example"
},
{
"Key": "aws:ec2launchtemplate:version",
"Value": "1"
},
{
"Key": "HashiCorp-Learn",
"Value": "aws-default-tags"
},
{
"Key": "Environment",
"Value": "Test"
}
]
Override default tags
You may occasionally need to override the default tags to customize a resource.
When you define the same tag in both the default_tags
configuration in the
provider and on a resource, the resource-specific tag overwrites the default
setting.
Add the following configuration to your aws_instance.example
resource in
main.tf
.
main.tf
resource "aws_instance" "example" {
ami = data.aws_ami.ubuntu.id
instance_type = "t2.micro"
tags = {
Service = "Custom"
ManagedBy = "Resource"
}
}
Run terraform apply
again to update the tags on the instance. Notice that the
execution plan shows updates to two fields, tags
and tags_all
. The tags
attribute represents the resource-specific tags in Terraform state, while
tags_all
is the total of the resource tags and the default tags specified on
the provider.
Respond yes
to the prompt to confirm the change.
$ terraform apply
##...
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
~ update in-place
Terraform will perform the following actions:
# aws_instance.example will be updated in-place
~ resource "aws_instance" "example" {
id = "i-06a3a837c7b181eb9"
~ tags = {
+ "ManagedBy" = "Resource"
+ "Service" = "Custom"
}
~ tags_all = {
+ "ManagedBy" = "Resource"
+ "Service" = "Custom"
# (2 unchanged elements hidden)
}
# (27 unchanged attributes hidden)
# (5 unchanged blocks hidden)
}
Plan: 0 to add, 1 to change, 0 to destroy.
Do you want to perform these actions in workspace "learn-terraform-aws-default-tags"?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
aws_instance.example: Modifying... [id=i-06a3a837c7b181eb9]
aws_instance.example: Modifications complete after 4s [id=i-06a3a837c7b181eb9]
Apply complete! Resources: 0 added, 1 changed, 0 destroyed.
Outputs:
asg_id = "terraform-20210719192917609900000003"
instance_id = "i-06a3a837c7b181eb9"
Inspect the updated tags using the AWS CLI. Notice that the EC2 instance's
tags have replaced the default Service
tag.
$ aws ec2 describe-tags --region us-east-2 --filters "Name=resource-id,Values=$(terraform output instance_id)"
{
"Tags": [
{
"Key": "Environment",
"ResourceId": "i-04a84802a4bf1f0e9",
"ResourceType": "instance",
"Value": "Test"
},
{
"Key": "ManagedBy",
"ResourceId": "i-04a84802a4bf1f0e9",
"ResourceType": "instance",
"Value": "Resource"
},
{
"Key": "Service",
"ResourceId": "i-04a84802a4bf1f0e9",
"ResourceType": "instance",
"Value": "Custom"
}
]
}
Destroy infrastructure
Run terraform destroy
to clean up your provisioned infrastructure. Respond
yes
to the prompt to confirm the operation.
$ terraform destroy
##...
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
- destroy
Terraform will perform the following actions:
##...
Plan: 0 to add, 0 to change, 3 to destroy.
Changes to Outputs:
- instance_id = "i-06a3a837c7b181eb9" -> null
- asg_id = "terraform-20210719192917609900000003" -> null
Do you really want to destroy all resources in workspace "learn-terraform-aws-default-tags"?
Terraform will destroy all your managed infrastructure, as shown above.
There is no undo. Only 'yes' will be accepted to confirm.
Enter a value: yes
##...
Destroy complete! Resources: 3 destroyed.
If you used HCP Terraform for this tutorial, after destroying your resources, delete the learn-terraform-aws-default-tags
workspace from your HCP Terraform organization.
Next steps
In this tutorial, you configured and overrode default tags for AWS resources. You also learned how to add default tags to Auto Scaling groups using dynamic blocks. To learn more about the configuration and concepts used in this tutorial, review the following:
- Learn how to query resources using data sources.
- Review how to create dynamic configuration using
for_each
blocks. - Read the AWS white paper on tagging strategies.