Using Terragrunt and Anchor Tags for Infrastructure Management
Terragrunt is a powerful tool that extends Terraform to help manage infrastructure with ease, particularly in large-scale, modular environments. It enables the use of DRY (Don’t Repeat Yourself) principles by reusing configurations across multiple environments. Incorporating the concept of anchor tags—or logical links and references—into a Terragrunt workflow can make managing cloud infrastructure even more efficient. These tags allow for better navigation, organization, and reusability of modules and resources, improving the clarity of complex infrastructure.
Here’s how anchor tags can be applied effectively in Terragrunt setups.
1. What Are Anchor Tags in Terragrunt?
In Terragrunt, anchor tags function conceptually as references or logical labels that link components together across multiple modules or hierarchical configurations. They:
- Simplify navigation between different layers (e.g., environments, modules, and resources).
- Enable better parameterization and modularization.
- Improve clarity in configurations by creating reusable “pointers” to shared settings.
2. Structure of Terragrunt with Anchor Tags
A typical Terragrunt structure includes:
- Root Directory: Contains global configurations shared across environments (e.g., remote state storage, providers).
- Environment Directories: Separate directories for
prod
,staging
, anddev
environments. - Module Directories: Shared Terraform modules for resources like networking, compute, or storage.
Anchor tags in this context can be applied through:
- HCL variables and outputs to create reusable links.
- Terragrunt configurations (e.g.,
terragrunt.hcl
) to define dependencies between modules.
3. Using Anchor Tags for Efficient Resource Linking
Example 1: Shared Variables for Cross-Module References
Define anchor-like variables at the root level that can be referenced in child modules.
terragrunt.hcl
in the root directory:
inputs = {
common_tags = {
environment = "prod"
owner = "team-infra"
}
vpc_id = "vpc-123456" # Anchor tag for VPC
}
Child modules or environment-specific configurations can reference these tags to avoid redundancy.
terragrunt.hcl
in prod/network/
:
include {
path = find_in_parent_folders()
}
inputs = {
tags = merge(local.common_tags, { module = "network" })
vpc_id = local.vpc_id # Reuse anchor tag
}
This ensures consistency across modules and simplifies updates.
Example 2: Dependency Injection
Use Terragrunt’s dependency
blocks as logical anchor tags to link modules together. For example, link a vpc
module with a subnet
module:
terragrunt.hcl
in prod/vpc/
:
inputs = {
vpc_name = "prod-vpc"
cidr = "10.0.0.0/16"
}
terragrunt.hcl
in prod/subnet/
:
dependency "vpc" {
config_path = "../vpc" # Anchor tag pointing to VPC configuration
}
inputs = {
vpc_id = dependency.vpc.outputs.vpc_id
subnet_cidr_blocks = ["10.0.1.0/24", "10.0.2.0/24"]
}
This creates a clear dependency chain, linking the subnet module to the VPC module using anchor tags.
4. Benefits of Anchor Tags in Terragrunt
a. Consistent Environment Management
- Anchor tags simplify the process of creating multiple environments (e.g.,
dev
,staging
,prod
) by referencing shared configurations. - Using tags like
common_tags
ensures that all resources are consistently labeled for tracking and governance.
b. Reduced Duplication
- Tags prevent duplication by allowing configurations to reference reusable variables, outputs, or dependencies.
- This aligns with Terragrunt’s goal of enforcing DRY principles.
c. Enhanced Collaboration
- Logical tags and dependencies provide clear, actionable links for teams, making configurations easier to understand.
- New team members can quickly grasp relationships between modules.
d. Easier Maintenance
- Updating a single tag or variable cascades changes throughout all dependent configurations, reducing maintenance overhead.
- For example, changing a VPC ID in the root configuration automatically updates all dependent modules.
5. Example: Complete Terragrunt Structure with Anchor Tags
Directory Structure:
├── live
│ ├── prod
│ │ ├── vpc
│ │ │ └── terragrunt.hcl
│ │ ├── subnet
│ │ │ └── terragrunt.hcl
│ ├── staging
│ │ ├── vpc
│ │ │ └── terragrunt.hcl
│ │ ├── subnet
│ │ │ └── terragrunt
Here’s how each component is structured and uses anchor tags for efficient management:
6. Terragrunt Configuration Examples
Root-Level Configuration
The root directory (live/terragrunt.hcl
) contains shared configurations, such as remote state storage and common inputs.
terragrunt.hcl
at the root level:
remote_state {
backend = "s3"
config = {
bucket = "my-terraform-state"
key = "${path_relative_to_include()}/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-lock-table"
}
}
inputs = {
common_tags = {
team = "team-infra"
environment = "shared"
}
}
This setup acts as an anchor for shared state and common inputs, propagating them to all child configurations.
Environment-Level Configuration
Each environment (prod
, staging
, etc.) has its own terragrunt.hcl
file. Anchor tags reference root-level configurations and define environment-specific inputs.
terragrunt.hcl
in prod/
:
include {
path = find_in_parent_folders()
}
inputs = {
environment_name = "prod"
additional_tags = {
project = "critical-app"
}
}
This configuration inherits the shared remote state and common_tags
from the root, adding environment-specific tags.
Module-Level Configuration
Each module (e.g., vpc
, subnet
) defines specific resources and uses dependencies to link modules together.
VPC Module: prod/vpc/terragrunt.hcl
include {
path = find_in_parent_folders()
}
inputs = {
vpc_name = "prod-vpc"
cidr = "10.0.0.0/16"
tags = merge(local.common_tags, { module = "vpc" })
}
Subnet Module: prod/subnet/terragrunt.hcl
include {
path = find_in_parent_folders()
}
dependency "vpc" {
config_path = "../vpc"
}
inputs = {
vpc_id = dependency.vpc.outputs.vpc_id
subnet_cidr_blocks = ["10.0.1.0/24", "10.0.2.0/24"]
tags = merge(local.common_tags, { module = "subnet" })
}
Here, the dependency
block acts as an anchor, linking the subnet
module to the vpc
module. Any changes to the vpc
outputs (e.g., vpc_id
) automatically update the dependent configurations.
7. Advantages of Anchor Tags in This Setup
a. Centralized Management
By defining shared inputs and remote state in the root-level configuration, teams can manage changes centrally, with updates cascading throughout the hierarchy.
b. Logical Dependencies
Dependencies between modules are clearly defined using Terragrunt’s dependency
block, making relationships between resources explicit and traceable.
c. Modular and Reusable Design
Anchor tags (e.g., vpc_id
and common_tags
) create reusable building blocks, enabling rapid deployment of additional environments or resources with minimal duplication.
d. Simplified Troubleshooting
When issues arise, anchor tags and dependencies provide a clear path for tracing and resolving problems across modules.
8. Conclusion
By integrating the concept of anchor tags into a Terragrunt-based infrastructure setup, teams can achieve a modular, maintainable, and scalable architecture. Logical linking of resources, environments, and modules streamlines cloud infrastructure management, reduces duplication, and enhances collaboration.
As cloud environments grow in complexity, leveraging tools like Terragrunt alongside a clear system of anchor tags ensures infrastructure remains organized, efficient, and easy to manage. Whether you’re deploying a single application or managing a multi-cloud strategy, this approach provides a robust foundation for modern Infrastructure as Code.