Terragrunt Default Tags

 ·  ☕ 4 min read

An approach to adding tags to all resources deployed by terragrunt

This page describes a method to adding a set of default tags to all resources that can be tagged in an AWS account (other terraform providers may be compatible)
More specifically, all resources deployed by terraform / terragrunt in a git repository.


Setup

First I should mention how I have set up the various terragrunt and terraform code, modules and repositories.

  • Each Terraform module is in a separate git repository.
  • Each AWS account has it’s own git repository.
  • The account repository has a root configuration (terragrunt.hcl) that configures the remote state.
  • All modules in the repo pull in the remote state configuration from the root terragrunt.hcl using the ‘include’ block.
  • The account repository has a terragrunt config file (terragrunt.hcl) in a separate folder per module, sometimes multiple modules are grouped together under a folder.

Thus an eaxample of an account repository:

.
├── terragrunt.hcl
├── module 1/
│   └── terragrunt.hcl
└── module group/
    ├── module 2/
    │   └── terragrunt.hcl
    └── module 3/
        └── terragrunt.hcl

Step 1 - Terraform Module

To propagate the tags to all resources deployed by a terraform module, that module needs to include a small addition.

Since AWS provider version 1.38.0 there has been the functionality to provide default tags, that then add those tags to all taggable resources.
If you have not updated terraform in some time, you might not be able to download the latest provider, see this link for details: https://discuss.hashicorp.com/t/terraform-updates-for-hcsec-2021-12/23570

The module needs to have a variable for the default tags which is then used on the provider block.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
variable "default_tags" {
    type = map
    value = {
        modulePath = "UNDEFINED"
    }
}

provider "aws" {
    region = "ap-southeast-2"
    default_tags {
        tags = var.default_tags
    }
}

Again, this needs to be added to all modules that you want the tags to be propagated to.

Step 2 - Account Repository

You can set the default tags for a module using either tags set in the module’s terragrunt.hcl or defaults set for the whole repo.
(More advanced setups allow you to have intermediary configuratition files, e.g. config for a group of modules)

To add tags for the specific module, simply add a ‘default_tags’ parameter to the module’s inputs block.

1
2
3
4
5
6
inputs = {
    ...
    default_tags = {
        exampleTag = "blah blah blah"
    }
}

Alternatively, you can add the default_tags parameter to an inputs block in the root terragrunt.hcl (the one that includes the remote state configuration). Each module’s terragrunt.hcl should have an include block that is pulling in the root terragrunt.hcl, thus anything in the root inputs block should be passed in at runtime.

This means that any resource (deployed by terraform using an updated module, see step 1) will have tags defined in the root of the repository (unless the tags are overridden in the particular module’s terragrunt.hcl).

Additional - modulePath Tag

A major problem with IAC is the ability to quickly identify the code that deployed a certain resource.
It is not uncommon that you know a resource is failing in misconfigured but when there are many modules deployed into an account, how do you know which module deployed that resource?

Using this approach, it is possible to add a dynamic tag that defines the path from the root of the repo to the module that deployed the resource.

A very easy way to do this is to use the built-in function relative_path_to_include().

Note: The path that relative_path_to_include() is relative to can catch you up. If you have it defined in the root terragrunt.hcl and run terragrunt from there (e.g. with the ‘run-all’ command) you will be fine.

Add the tag in the root terragrunt.hcl, like so:

1
2
3
4
5
6
7
inputs = {
    ...
    default_tags = {
        exampleTag = "blah blah blah"
        modulePath = relative_path_to_include()
    }
}

The result of this configuration would be that all resources deployed by ‘module 2’ (see example repo) would have the tag ‘modulePath’ = ‘module group/module 2’.


Kieran Goldsworthy
WRITTEN BY
Kieran Goldsworthy
Cloud Engineer and Architect


What's on this Page