Default Tags for Terraform AWS Provider is finally here
Tags: terraform, aws, cloud
Published: 2021-05-16 10:47:01

Default tags for Terraform AWS provider had been in the works since I started using Terraform a couple of years ago. Now that it is finally here, does it live up to its expectation?

# What is Default Tags?

Default Tags allows its user to tag all AWS resources that support tags with the exception of the `aws_autoscaling_group` resource. Default Tags are defined in the AWS provider configuration, and AWS resources configured with that provider will inherit `default_tags`. A sample usage could be:
```hcl
provider "aws" {
  region = "ap-southeast-1"
  default_tags {
    tags = {
      Environment = "dev"
      Project     = "example project"
      Terraform   = true
  }
```
You can read more about it [here](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/guides/resource-tagging#propagating-tags-to-all-resources) and [here](https://www.hashicorp.com/blog/default-tags-in-the-terraform-aws-provider).

# Default Tags in different scenarios
From the [official blog post](https://www.hashicorp.com/blog/default-tags-in-the-terraform-aws-provider), it states that individual resource tags will take precedence over `default_tags`. Let’s see it in action with a few scenarios and observe its `terraform plan` output.

### Scenario 1: Only resource tags, no `default_tags`
```hcl
provider "aws" {
  region = "ap-southeast-1"
}
resource "aws_vpc" "tagging_test_vpc" {
  cidr_block = "10.0.0.0/16"
  tags = {
    Name        = "tagging-test"
    Environment = "dev"
    Terraform   = true
  }
}
```
`terraform plan` output:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zx3v939miwv71uoq0nsx.png)

Here, we can see the existence of a `tags_all` attribute that has the same value as the original `tags` attribute. That being said, I’ve noticed this `tags_all` attribute for some time now in the newer versions of AWS provider. Let’s move on to the next scenario.

### Scenario 2: Only `default_tags`, no resource tags
```hcl
provider "aws" {
  region = "ap-southeast-1"
  default_tags {
    tags = {
      Environment = "stg"
      Name        = "tagging-test-3"
  }
}
resource "aws_vpc" "tagging_test_vpc" {
  cidr_block = "10.0.0.0/16"
}
```
`terraform plan` output:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jzuyj6jfo9rym6zf2sj6.png)

Without resource tags, the `tags` attribute disappears, leaving only the `tags_all` attribute with the value inherited from `default_tags` from the AWS provider configuration.

### Scenario 3: Conflicting tags
```hcl
provider "aws" {
  region = "ap-southeast-1"
  default_tags {
    tags = {
      Environment = "stg"
      Name        = "tagging-test-3"
  }
}
resource "aws_vpc" "tagging_test_vpc" {
  cidr_block = "10.0.0.0/16"
  tags = {
    Name        = "tagging-test"
    Environment = "dev"
    Terraform   = true
  }
}
```
`terraform plan` output:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/litqt2pgtxrppaynwg9t.png)

Similar to what the official blog post mentioned, we can observe that resource tags take precedence over default tags when there is a conflict of tag name/key.

### Scenario 4: Non-conflicting tags
```hcl
provider "aws" {
  region = "ap-southeast-1"
  default_tags {
    tags = {
      environment   = "stg"
      name          = "tagging-test-3"
      provisionedby = "Terraform"
  }
}
resource "aws_vpc" "tagging_test_vpc" {
  cidr_block = "10.0.0.0/16"
  tags = {
    Name        = "tagging-test"
    Environment = "dev"
    Terraform   = true
  }
}
```
`terraform plan` truncated output:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/byfpov53amwqekotrsxz.png)

Since tag names/keys are case-sensitive, all the default_tag tags in this example will be effected for `aws_vpc`. The `tags_all` attribute shows a combined list from default and resource tags, while the `tags` attribute only shows the resource tags.

# How this could affect your Terraform State design
In a medium-to-large-sized project, Terraform state separation is one of the early design considerations a team needs to settle on. If you don’t know what state is, check out [this documentation](https://www.terraform.io/docs/language/state/purpose.html) first.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oamsv0ng4w653cm51nzy.png)
<figcaption>
From <a href="https://learn.hashicorp.com/tutorials/terraform/state-import?in=terraform/state">HashiCorp</a>
</figcaption>

Each Terraform state culminates in a state file, and each state file has its own Terraform and provider configurations. Since default tags are a configured on the AWS provider level, being able to enforce different default tags in different states can make any mandatory organizational tagging requirements a breeze.

For example, if your organization has different tag values for each application, it might make sense to separate all applications into it’s own state and enforce their unique application tags at the provider level.

Terraform state design is a topic I’ve always seen a lot of discussion about. I will write about it in a future post.

# Closing Thoughts
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tbljr6gdt523q27n660l.png)

It’s good to know that Terraform and the AWS Provider is still well supported and constantly improved on. All in all, Terraform as an IaC tool is reaching a level of maturity that I’ve been looking forward to. With the current Terraform 0.15 touted as the “beginning of the pre-release period leading up to Terraform 1.0”, I think Terraform users can expect a lot of exciting and useful releases in the coming weeks and months.