How do I enforce tagging using Terragrunt #756
Replies: 1 comment
-
One question that comes up on the items above is how to override the tags. There are a few scenarios for this: Scenario 1: overriding tags within a moduleLet's say you've configured provider "aws" {
default_tags {
tags = {
Environment = "test"
Name = "example"
}
}
} However, in some module, you want to override these tags in a specific resource. You can do so by using the resource "aws_vpc" "example" {
# ..other configuration...
tags = {
Name = "example-vpc"
}
} Any
Scenario 2: overriding tags on a per-environment / per-module basisAnother scenario may be that you want to override tags to different values in different live environments. For example, let's again assume you have provider "aws" {
default_tags {
tags = {
Environment = "test"
Name = "example"
}
}
} And in your variable "tags" {
description = "Custom tags to set on the VPC"
type = map(string)
default = {}
}
resource "aws_vpc" "example" {
# ..other configuration...
tags = var.tags
} Now you can optionally override the tags with different values in different environments. E.g., In stage, you might set: tags = {
Name = "example-vpc-stage"
} And in prod, you might set: tags = {
Name = "example-vpc-prod"
} Scenario 3: supporting tag overrides globally with TerragruntOne other neat thing you can do with Terragrunt is to add support for overriding the tags on all resources, globally. This way, you don't have to add a To do that, you first create a root locals {
# The default tags to apply in all environments
default_tags = {
Environment = "test"
Name = "example"
}
# Load an overrides.yml file in any Terragrunt folder, or fallback to {} if none is found
overrides = try(yamldecode(file("${get_terragrunt_dir()}/overrides.yml")), {})
# Read the override tags, if any, from overrides.yml, or fallback to {} if none are found
override_tags = lookup(local.overrides, "tags", {})
# The final tags to apply to all resources are a merge between the default tags and override tags
tags = merge(local.default_tags, local.override_tags)
}
generate "provider" {
path = "provider.tf"
if_exists = "overwrite"
contents = <<EOF
provider "aws" {
default_tags {
tags = ${jsonencode(local.tags)}
}
}
EOF
} This structure defines some default tags to apply to all modules, but it also allows each module to optionally define an So, for example, in # Include the root terragrunt.hcl config
include "root" {
path = find_in_parent_folders()
} And also in tags:
Name: vpc-stage In tags:
Name: vpc-prod In other words, any of your Terragrunt modules can now include an |
Beta Was this translation helpful? Give feedback.
-
I'm adapting an answer originally written by @brikis98.
Let's take a look at some options for solving this:
Use the Terraform AWS Provider
The AWS Provider supports the default_tags parameter. This works with all AWS resources except
aws_autoscaling_group
. Here's an example:But this has a key limitation: you have to ensure every single module specifies those tags in its
provider
block. There is no way to "reuse" that logic with Terraform. You just have to manually copy/paste it into every single module you create. So it’s very error prone and easy to miss it.Static analysis
You could add static analysis to the CI / CD pipeline of your module repos that scans every module and blocks merge if that module doesn’t specify the proper
default_tags
block. See this example using tfsec.Use
generate
blocks with TerragruntTerragrunt supports a generate block. Instead of hard-coding the
provider
block in every single module, you can ensure that every repo that uses Terragrunt has a single, centralgenerate
block used by everything in that repo. Thatgenerate
block can include thedefault_tags
you want.Here's an example of how Gruntwork handles this when we set up new DevOps foundations customers:
Tracked in ticket #110367
Beta Was this translation helpful? Give feedback.
All reactions