Sept. 20, 2021, 1:03 p.m.
Posted by soar

Terraform and "Default Tags"

There is a nice feature in Terraform AWS provider which is named default_tags. The idea is very simple: now you don't need to place tags block in each resource. You can define it once per provider and these tags will be applied to all (or almost all) resources that support tagging.

Before:

provider "aws" {}

locals {
  default_tags = {
    managed_by = "terraform"
  }
}

resource "resource_type" "my_resource" {
  tags = merge(
    local.default_tags,
    {
      Name     = "resource-name"
      othertag = "othervalue"
    }
  )
}

Now:

provider "aws" {
  default_tags {
    managed_by = "terraform"
  }  
}

resource "resource_type" "my_resource" {
  tags = {
    Name     = "resource-name"
    othertag = "othervalue"
  }
}

Clear and very useful. With a few lines of code, you can mark all the resources which are managed by IaC. But, there are two things to know.

Applying to the existing infrastructure

It looks like a good idea to update all resources in the existing infrastructure with changing just a few lines of code. But I found that some resources can't handle this change properly. For me they were aws_ecs_task_definition and aws_iam_policy, but I think it depends on a common thing: both resources used some kind of templated files - data.aws_iam_policy_document.<name>.json and data.template_file.<name>.rendered.

But, there is a solution to do this. Just add this line to all resources, that are affected and that are going to be replaced:

resource "aws_iam_policy" "my_resource" {
  lifecycle { ignore_changes = all }
}

When your plan will be clear, and you see, that all changes is just adding your tags - apply it and remove the line. The second apply will only add tags to untagged resources without recreating them.

Not all resources are supported yet

Be careful, when changing your code to make it store tags in one place. For example, some of nested resources definitions are not supported by global tagging. For example - root_block_device.

resource "aws_instance" "my_instance" {
  # Tags for an instance will be automatically merged with global "default_tags"
  tags = {
    Name = "my-instance"
  }

  # But tags for the block-device should be merged manually
  root_block_device {
    tags = merge(
      local.default_tags,
      {
        Name = "my-instance-root-volume"
      }
    )
  }
}

Comments