Sling Academy
Home/DevOps/How to use Terragrunt to manage Terraform config

How to use Terragrunt to manage Terraform config

Last updated: February 03, 2024

Introduction

For developers working with infrastructure as code, managing complexity and avoiding duplication can be challenging as projects grow. Terragrunt is a thin wrapper that provides extra tools for keeping your Terraform configurations DRY (Don’t Repeat Yourself), working with multiple Terraform modules, and managing remote state more easily. In this guide, we’ll walk through how to use Terragrunt to simplify your Terraform configuration management, from basic to advanced use cases, along with code examples and outputs where applicable.

Getting Started with Terragrunt

Before diving into Terragrunt, make sure you have both Terraform and Terragrunt installed. Terragrunt is designed to work with all Terraform versions but it’s always good practice to keep both tools up to date. The installation instructions for each platform are available on the respective websites of Terraform and Terragrunt.

Once installed, the simple structure of a Terragrunt configuration looks something like this:

terraform {
  source = "./modules"
}

include {
  path = find_in_parent_folders()
}

inputs = {
  name = "example-project"
}

This configuration tells Terragrunt where to find the Terraform modules it should use (`source`) and allows it to inherit configuration from parent folders (`include`), a powerful feature for managing configurations across environments. In the `inputs` section, you define variables specific to this configuration.

Organizing Your Infrastructure with Terragrunt

One of the main advantages of Terragrunt is its ability to keep your infrastructure code DRY. By using the `include` block and the `find_in_parent_folders()` function, you can have a single terragrunt.hcl file in a root directory that defines common settings for all of your Terraform projects, reducing repetition.

// base/terragrunt.hcl
remote_state {
  backend = "s3"
  config = {
    bucket         = "my-terraform-state-bucket"
    key            = "${path_relative_to_include()}/${terraform.workspace}/terraform.state"
    region         = "us-east-1"
    encrypt        = true
    dynamodb_table = "terraform-locks"
  }
}

Working with Multiple Environments

Managing multiple environments (development, staging, production) is where Terragrunt really shines. By creating directories for each environment and placing a terragrunt.hcl file in each one, you can customize configurations per environment while inheriting shared settings from a parent configuration.

// environments/dev/terragrunt.hcl
terraform {
  source = "../../modules/vpc"
}

include {
  path = find_in_parent_folders()
}

inputs = {
  environment = "dev"
  vpc_cidr = "10.0.0.0/16"
}

Advanced Configuration with Terragrunt

For more advanced use cases, Terragrunt allows you to leverage Terraform’s ability to call external data sources or use hooks to execute scripts before or after Terraform commands. For instance, a before_hook could be used to lint Terraform files before applying them.

before_hook "terraform_fmt" {
  commands     = ["apply", "plan"]
  execute      = ["terraform", "fmt", "-check"]
}

Importing Remote State

Another powerful feature of Terragrunt is the ability to easily import remote state from various backends, simplifying state management across multiple Terraform executions and projects. Below example demonstrates accession of a state file stored in S3:

dependency {
  name = "vpc"
  config_path = "../vpc"
}

inputs = {
  vpc_id = dependency.vpc.outputs.vpc_id
}

By referring to another Terragrunt configuration as a dependency, you can dynamically read its outputs and use them in your configuration.

Conclusion

Using Terragrunt to manage your Terraform configurations can significantly reduce complexity and duplication in your infrastructure code. By following the practices outlined in this guide, you can streamline your infrastructure management process, making it more maintainable and scalable. Whether you’re managing a single project or multiple environments, Terragrunt offers tools and features that enhance Terraform’s capabilities, making infrastructure as code even more powerful.

Next Article: Using Rover to visualize Terraform resource dependencies

Previous Article: How to use Terraform templates

Series: Terraform Tutorials

DevOps

You May Also Like

  • How to reset Ubuntu to factory settings (4 approaches)
  • Making GET requests with cURL: A practical guide (with examples)
  • Git: What is .DS_Store and should you ignore it?
  • NGINX underscores_in_headers: Explained with examples
  • How to use Jenkins CI with private GitHub repositories
  • Terraform: Understanding State and State Files (with Examples)
  • SHA1, SHA256, and SHA512 in Terraform: A Practical Guide
  • CSRF Protection in Jenkins: An In-depth Guide (with examples)
  • Terraform: How to Merge 2 Maps
  • Terraform: How to extract filename/extension from a path
  • JSON encoding/decoding in Terraform: Explained with examples
  • Sorting Lists in Terraform: A Practical Guide
  • Terraform: How to trigger a Lambda function on resource creation
  • How to use Terraform templates
  • Understanding terraform_remote_state data source: Explained with examples
  • Jenkins Authorization: A Practical Guide (with examples)
  • Solving Jenkins Pipeline NotSerializableException: groovy.json.internal.LazyMap
  • Understanding Artifacts in Jenkins: A Practical Guide (with examples)
  • Using Jenkins with AWS EC2 and S3: A Practical Guide