Back to all blog posts
Guide

How Terramate adds superpowers to Terragrunt in just 5 minutes

This guide demonstrates how Terramate can supercharge Terragrunt by adding advanced capabilities in just a few minutes without changing any existing configuration.

Picture of Soren Martius
Sören Martius
· 11 min read
How Terramate adds superpowers to Terragrunt in just 5 minutes

How Terramate adds superpowers to Terragrunt in just 5 minutes

Introduction

As Terraform and OpenTofu projects grow, teams often manage an ever-increasing code base, complexity, and config sprawl. Terramate helps overcome those challenges. But what if you are a Terragrunt user?

Don’t worry, we've got you covered with our Terragrunt Integration.

This guide demonstrates how you can use Terramate to supercharge existing Terragrunt projects by adding advanced capabilities in just a few minutes and without changing any existing configuration.

Here’s a quick overview of some superpowers that you can add to Terragrunt with Terramate:

  • Orchestration with Change Detection to automatically detect and execute modules that contain changes only using terragrunt plan and terragrunt apply .
  • GitOps automation workflows in GitHub Actions (or any other CI/CD) to automate Terragrunt with plan previews in Pull Requests in your CI/CD without requiring any additional tooling such as Atlantis.
  • Drift detection and reconciliation to keep your Terragrunt modules drift-free with scheduled workflows in GitHub actions.
  • Observability and Visibility to understand the health and infrastructure managed in your modules.

Let’s dive right in!

Why use Terramate with Terragrunt

There is a common misunderstanding that depending on your preference, you must decide between Terramate or Terragrunt and that both can’t be used together.

That’s wrong!

While Terramate has some overlapping but not conflicting capabilities with Terragrunt, we designed Terramate so that it can be integrated and used in any existing project and with any third-party tooling that you already use and love - in a non-intrusive way and without changing any configuration.

In a nutshell, Terramate is an Infrastructure as Code management platform consisting of an open-source CLI that optionally pairs with a fully managed cloud service. One of the most important features in the Terramate CLI is orchestration, which allows you to orchestrate any command in stacks. That means you can orchestrate Terragrunt and, subsequently, Terraform along with Terramate.

Terramate and Terragrunt are a great matchYip, you read this right. Terramate and Terragrunt work well together!

But why should you consider adding Terramate to your Terragrunt Project?

Better Orchestration with Change Detection

With Terragrunt, you can only execute a single or all modules (e.g., terragrunt run-all apply and terragrunt run-all apply ). This becomes challenging, especially when running Terragrunt in CI/CD. Terragrunt doesn't have any advanced orchestration functionality, and due to the lack of change detection, it is impossible to detect and execute modules that have changed, which can lead to long execution run times and a large blast radius.

You can overcome this by orchestrating Terragrunt using the Terramate orchestration and change detection.

For example, the following command orchestrates terragrunt apply in all Terragrunt modules that contain changes:

terramate run --changed -- terragrunt apply 

The change detection capabilities in Terramate are based on Git and cover Terraform, OpenTofu, and Terragrunt-specific use cases:

  • It can detect changes in referenced Terraform modules to mark a stack as changed
  • It can parse Terragrunt configuration to detect changes in:
    • included files (by processing include  blocks)
    • dependencies (dependency  and dependencies  blocks)
    • file read by function calls (read_terragrunt_config()read_tfvars_file()  , etc)
    • local terraform.source  blocks

In addition, Terramate orchestration can be leveraged to run any command **in Terragrunt modules. Remember, Terragrunt is a wrapper that doesn’t allow you to run custom commands.

Running Terragrunt in Automation

Automating Terragrunt in CI/CD is hard, and no pre-configured integration exists. Even worse, most of the examples out there want you to execute terragrunt run-all apply in every single pipeline run, which means you would always execute all modules, defeating the value add of using multiple root modules (aka stacks) in the first place.

Terramate CLI integrates well with GitHub Actions, GitLab CI/CD, and Bitbucket Pipelines, allowing you to orchestrate and automate Terragrunt with fully configurable GitOps workflows securely and cost-effectively by reusing compute and security already in place. With Terramate, you can configure apply-and-merge or merge-and-apply workflows, provide previews in Pull Requests and configure custom approval workflows using policies.

The example below shows how plan previews look in GitHub Pull Requests using Terramate in GitHub Actions:

preview of Terragrunt changesVisibility, Observability, and Insights

Terragrunt is often used to simplify and standardize environments at scale. While this is great, it can be challenging for teams to keep an overview of what infrastructure is managed in Terragrunt modules, especially when working with multiple repositories.

Terramate Cloud provides an overview of all your Terragrunt modules, deployments, drift detection runs, and more, which improves visibility, insights, and observability.

This works because Terramate CLI can sync data from orchestrated commands such as terragrunt plan to Terramate Cloud. For example, the following command creates a plan in each Terragrunt module and syncs those to Terramate Cloud.

terramate run \
  --parallel=5 \
  --cloud-sync-preview \
  --cloud-sync-terraform-plan-file=out.tfplan \
  --terragrunt \
  -- \
  terragrunt plan -out out.tfplan -detailed-exitcode 

Execution is done in parallel, and syncing plans to Terramate Cloud allows us to review plans per stack. program outputIt’s important to understand that Terramate never syncs sensitive values to Terramate Cloud. Instead, Terramate CLI removes all sensitive values, such as secrets, and only a sanitized version of the plan is synced. Terramate Cloud does not have or require access to your state files, code, or cloud accounts, making it very secure to use.

Drift Detection and Reconciliation

Drifts in IaC are untracked changes, meaning your deployed resources have changed and no longer match the desired configuration. Such untracked changes pose risks with varied severity and have the potential to drastically impact your managed infrastructure's reliability, security, or performance. With Terramate, you can use scheduled workflows in your CI/CD to detect and reconcile drift.

The drift detection works by running a scheduled terragrunt plan on all stacks and sending the results to Terramate Cloud. The following command runs a drift detection in all Terragrunt modules and syncs the result to Terramate Cloud.

terramate run \
  --cloud-sync-drift-status \
  --cloud-sync-terraform-plan-file=drift.tfplan \
  --continue-on-error \
  --terragrunt \
  -- \
  terragrunt plan -out drift.tfplan -detailed-exitcode -lock=false

You can then reconcile drifted stacks by using the --cloud-status filter in the Terramate orchestration to run terragrunt apply in all drifted stacks:

terramate run \
  --cloud-status=drifted \
  --cloud-sync-deployment \
  --cloud-sync-terraform-plan-file=drift.tfplan \
  --terragrunt \
  -- \
  terragrunt apply -input=false -auto-approve -lock-timeout=5m out.tfplan

If you only want to enable auto-reconciliation for specific stacks, you can archive this using tags. Additionally, you can configure manual approval workflows to review a reconciliation workflow before running it.

Getting Started

Alright, let’s get started. In this guide, we will use Gruntwork’s well-known reference architecture. It’s an example of using Terragrunt in a production-grade manner and the perfect starting ground to explore how Terramate can provide immediate value to any Terragrunt project!

If you want to see the end result of this guide right away instead, feel free to take a look at our fork of the reference architecture that comes with all of the mentioned steps implemented below. It gives you an idea how the integration works.

Pre-requisites

Before we can dive in, we need to install Terramate, Terragrunt, and Terraform. You also need a working AWS account to deploy the infrastructure configured in the reference architecture. Please note that you can easily replace Terraform with OpenTofu if you wish.

  1. Install Terramate version v0.6.1  or newer.
  2. Install Terragrunt version v0.55.0  or newer.
  3. Install Terraform version v1.7.5 or OpenTofu v1.6.2 or newer.
  4. Configure your AWS credentials using one of the supported authentication mechanisms
  5. Sign up for a free Terramate Cloud account, which we will use to enable observability, visibility, drift control and Slack notifications for your Terragrunt modules. To learn how to set up and configure your account, see the docs at https://terramate.io/docs/cloud/signup/.

Configure the Reference Architecture

After setting up the required dependencies and creating your Terramate Cloud account, we can continue configuring and deploying the Terragrunt reference architecture with Terramate.

1. Clone the repository

Next, let’s clone the terragrunt-infrastructure-live-example repository so we can start getting our hands dirty.

git clone https://github.com/gruntwork-io/terragrunt-infrastructure-live-example

2. Configure Terramate

To configure Terramate in the repository, add the terramate.tm.hcl file in the root of the repository with the following configuration. Please replace the TG_BUCKET_PREFIX environment variable with a prefix of your choice and add the identifier of your Terramate Cloud organization.

terramate.tm.hcl

terramate {
  config {

    run {
      env {
        TG_BUCKET_PREFIX = "yourprefix-" # TODO: replace this with a unique prefix
      }
    }

    git {
      # Git configuration
      default_remote = "origin"

      # Safeguards
      check_untracked   = false
      check_uncommitted = false
      check_remote      = false
    }
    
    # Configure the namespace of your Terramate Cloud organization
    # Set this to the short name of your Terramate Cloud Organization
    cloud {
      organization = "terramate-demo"
     }
  }
}

This configuration takes care of a few things:

  • Enables the Terragrunt integration.
  • Sets the prefix required for your Terraform state bucket with the TG_BUCKET_PREFIX environment variable using Terramate to configure the running environment. Make sure that you replace yourprefix- with a prefix of your choice.
  • Disables the default safeguards in Terramate, which prevent you from orchestrating commands, such as terragrunt apply when you have files or changes that aren’t checked into your repository, and help you avoid applying code changes without having peers review those first. For production environments, we recommend you turn those on!

3. Updating the default branch to main

Gruntworks’ repository uses master as the default branch. Let’s update this to main and remove all ties to the upstream repo.

git checkout -b main
git config --global init.defaultBranch main  
git branch -D master
git remote remove origin

4. Configure AWS Account

We will use a single AWS to deploy the production and all pre-production environments such as prod , stage and qa .

Update the account.hcl file in prod/account.hcl as well as non-prod/account.hcl and set aws_account_id to your AWS account ID.

locals {
  aws_account_id = "XXXXXXXXXXXXXXX"
}

Et voila, the reference architecture is now configured and ready to deploy. Let’s take a look at how we can trigger the initial deployment with Terramate.

5. Import all Terragrunt modules to Terramate

In Terramate, features such as orchestration are based on stacks, which, at the bare minimum, are just directories that contain a stack.tm.hcl file, which can be used to configure a stack's metadata and orchestration behavior.

For Terramate to detect and orchestrate Terragrunt modules, we must declare all Terragrunt modules as stacks. To make this process as simple and fast as possible, Terramate comes with a built-in command. The create —-all-terragrunt command scans all available Terragrunt modules in your current repository and creates a stack.tm.hcl in each detected module.

terramate create --all-terragrunt

Created stack /non-prod/us-east-1/qa/mysql
Created stack /non-prod/us-east-1/qa/webserver-cluster
Created stack /non-prod/us-east-1/stage/mysql
Created stack /non-prod/us-east-1/stage/webserver-cluster
Created stack /prod/us-east-1/prod/mysql
Created stack /prod/us-east-1/prod/webserver-cluster

This is it! We can now use Terramate in our Terragrunt project. Try a few of the available commands to see how Terramate works.

List all stacks:

terramate list

Understand the order of execution:

terramate list --run-order

Orchestrate a command in all stacks

terramate run -- echo "hello world"

6. Deploy all stacks in the production environment

Now that we have our project configured let’s continue and deploy the infrastructure configured in prod . Since the reference architecture deploys a MySQL instance, we need to configure the DB password as an environment variable:

export TF_VAR_master_password="REPLACE_ME"

Note: We use the same password for all databases deployed in this example. In a real-world scenario, you should probably use different passwords for each database.

Next, let’s run terramate run terragrunt plan  to see the changes you will apply. In a nutshell: Terramate will traverse the dependency graph of Terragrunt modules and orchestrate the terragrunt plan in all modules sequentially.

Up on the initial orchestration of the terragrunt plan command, Terragrunt will create the Terraform state bucket for you if it’s non-existent.

terramate run terragrunt plan

terramate: Entering stack in /prod/us-east-1/qa/mysql
terramate: Executing command "terragrunt plan"
Remote state S3 bucket terragrunt-example-tf-state-prod-us-east-1 does not exist or you don't have permissions to access it. Would you like Terragrunt to create it? (y/n)

...

After reviewing the plan of each stack for correctness, you can apply the changes.

terramate run terragrunt apply

Congratulations, you just deployed the reference architecture.

Sync all Terragrunt modules to Terramate Cloud

Next, let’s sync our data to Terramate to get an overview of all our stacks.

To archive this, we need to authenticate Terramate CLI with Terramate Cloud.

terramate cloud login

This command authenticates the CLI by logging in to Terramate Cloud with the identity provider of your choice and will allow you to sync and fetch data to and from Terramate Cloud.

For example, terramate list --cloud-status=drifted can be used to retrieve a list of stacks that are marked as drifted from Terramate Cloud. You can also use the --cloud-status attribute to select stacks for orchestration. For example, terramate run --cloud-status=drifted -- terragrunt apply would run terragrunt apply in all drafted stacks to remediate drift.

To initially sync all stacks to the cloud, the most straightforward way is to run an initial drift detection in all stacks:

terramate run \
  --cloud-sync-drift-status \
  --cloud-sync-terraform-plan-file=drift.tfplan \
  --continue-on-error \
  --terragrunt \
  -- \
  terragrunt plan -detailed-exitcode -out drift.tfplan

After this, all managed stacks are synced and available in the stacks section of Terramate Cloud.

stacks

Enable GitOps CI/CD on GitHub Actions

In our repository you can find a few pre-configured GitHub actions workflows:

  • preview.yml Runs terragrunt plan for all changed stacks inside a Pull Request and provides a preview to review changes before merging to the main branch.
  • deploy.yml Runs terragrunt apply on all changed stacks when merging back to the main branch. We use the merge-and-apply strategy in this example and automatically apply all changes.

Copy those workflows to your repository and try introducing a change by, e.g., changing input parameters such as the allocated storage for each database. Once you create a new branch, commit the changes, and open a new Pull Request - Terramate will create a plan and associated preview for you inside the Pull Request and in Terramate Cloud.

Pull Request Preview

pull request preview

Terraform Cloud

Terramate cloudYou can send different outputs and previews to Terramate Cloud. For example, in addition to the Terraform plan you can send data and summaries from tools such as infracost, checkov, terrascan, tfsec and many others.

Using a Pull Request workflow to add changes and deploying those out on merge back to the main branch enables you to manage your cloud infrastructure fully automated by using GitOps principles. In addition, you can configure settings such as branch protection rules in GitHub to enforce reviews of changes introduced before allowing to merge PRs.

To enable the workflows, you need to create a GitHub Actions secret in your repository to configure the database password called MYSQL_PROD_MASTER_PASSWORD . We inject the password as a secret to avoid hard-coding secrets in our Terraform Configuration.

Actions Secrets & Variables

Enable Drift Detection and Reconciliation

In addition to the preview and deployment workflows explained above, you can find an additional workflow in the repository called drift-detection.yml.

This workflow runs a plan in all stacks every 6 hours and automatically remediates drift for stacks tagged with reconcile . Whenever this workflow detects one or more drifted stacks, it will mark them as drifted in Terramate Cloud and provide the drift details.

DeploymentsIn addition, if you configure the Slack integration in Terramate Cloud, you will receive Slack notifications about detected drift.

Slack notificationWe configured the drift detection to automatically reconcile drift in all stacks that are tagged with reconcile . For example, see added the tag to all stacks in the prod in our repository.

terramate-terragrunt-infrastructure-live-example/prod/us-east-1/prod/mysql/stack.tm.hcl

stack {
  name        = "mysql"
  description = "mysql"
  id          = "d28fe1cf-5ed0-4433-a939-34d6fe3fe473"
  tags        = ["reconcile"]
}

This is pretty useful because it allows you to configure whether stacks should be reconciled automatically or not. The handling of detected drift is also fully configurable. For example, you can easily add an approval step to the workflow to review a drift before reconciling it.

Summary

That’s it! In this guide, you learned how to use Terramate to overcome common challenges in Terragrunt. You can use this to quickly supercharge any Terragrunt project with orchestration, change detection, GitOps workflows, drift detection, observability, deployment notifications and more.

Feel free to give us feedback and ask any questions in our Discord community. You can also check out the example repository by cloning it and running it in your GitHub account.

Stay tuned for future articles. There’s a lot more stuff to learn that we haven’t covered in this article, such as the native code generation in Terramate, which helps you to keep your stacks DRY by generating files such as Terraform, OpenTofu, JSON, YML and more.

Soren is a co-founder and Chief Product Officer of Terramate. Before founding Terramate, he built cloud platforms for some of Europe's fastest-growing scaleups.