terraform-control is a boilerplate starter kit repo that will help you succeed in managing your infrastructure using Terraform with Terragrunt. We started with the example docs/repo maintained by the Gruntwork team but found there were still plenty of improvements to make.
Terraform and Terragrunt are both very powerful and extensible tools that offer an overwhelming amount of options on how to structure your repo. Use the patterns we laid out here so you can enjoy a scalable IaC code repository that won't bite you in the butt a few months down the line.
Prior to using this repo you should already have prerequisite knowledge of both Terraform and Terragrunt. Ideally you have already used Terraform in production and have become familiar with its pitfalls and shortcomings that make it difficult to maintain. Same for Terragrunt, even if it is less prone to these issues.
- Keep It Simple, Stupid. STAND UP! to your inner voice that is telling you that have a snowflake situation, and to bungle your whole infrastructure with bespoke scripts that only you can understand. Ask yourself instead, "Why do I feel empty inside all the time?"
- Stay up to date with Terragrunt's design patterns in terragrunt-infrastructure-live-example
- Be suited for organizations both small and large
- Have examples of how to create a complicated, multi-tier infrastructure while keeping the code DRY
- Provide guidance on how to pass in configuration data
- Keep the repo updated with solutions to problems that have caused us grief in the past
- Resist temptation to create "wrapper scripts" or any other layers of abstraction
In addition to Terraform and Terragrunt best practices:
- Stay DRY and be obsessive about it. No exceptions.
- No custom wrapper scripts or other layers of abstraction. Terragrunt is already enough of a wrapper.
modules/
directory only contains Terraform code and all variable data is set as avariable {}
live/
directory contains Terragrunt code with the configuration data (inputs {}
) that gets fed into the actual Terraform code inmodules/
- Limit the origin of configuration data to only one single source per each type of configuration data. We have three (3) possible types of configuration data. See section on Sources of Configuration Data for further explanation
User-defined Configuration is when a human defines a customizable variable. Examples: the instance-type of their EC2 instance, the number of instances in an ASG, setting an RDS instance Multi-AZ, etc.
- All user-defined configuration data is declared inside the
live/<env>/terragrunt.hcl
of the stack you are creating - Avoid using
terraform.tfvars
, or$ENVVAR
s, or any other method
Discovered Configuration Data are attributes of resources that Terraform has created. Examples: The VPC module needs to share subnet-id
data with an RDS module, the RDS module needs to share its endpoint
with the App module, etc.
- All variable configuration data that is shared between modules is done with AWS's SSM Parameter Store.
- This has the added benefit of being able to share data with 3rd party tools outside of Terraform (e.g. SAM, serverless-framework)
- Do not use
data.terraform_remote_state
, oroutputs {}
, or any other method.
Remote State Configuration Data is the information on the S3 bucket and DynamoDB table to use for your backend.config.{}
.
- Remote state configuration data is declared inside the file
config/remote_state.config
- Avoid hard coding the backend configuration
See each vendor's documentation for detailed installation docs. Below is a TL;DR for OSX people.
- Install terraform (We recommend using tfenv)
brew install tfenv && tfenv install latest
- Install terragrunt
brew install terragrunt
- Install
awscli
and configure it with your API keysbrew install awscli
aws configure
- Clone this repo
This is the only "stack" where we are forced to break just two rules: #1 - Use the local
backend with no remote locking. Commit the local state db into the git repo. #2 - Use wrapper process to populate the backend.config.{}
.
cp terraform/config/remote_state.config.example terraform/config/remote_state.config
- Edit
remote_state.config
to your needs cd terraform/live/global/terraform-remote-state
terragrunt apply
Now we are ready to create infrastructure.
This repo comes equipped an example of how you can launch a a webserver running on an EC2 Instance, and dependencies of a VPC and RDS MySQL instance.
cd terraform/live/stg
terragrunt apply-all
- Done! 🎉 Have a look around, and then:
terragrunt destroy-all
If you have an App Stack you want to add:
- Create
modules/myappstack
and define all of your Terraform code, or better yet just pull in a module from Terraform Module Registry - Following examples provided in this repo, create new
live/{stg,prod}/myappstack/terragrunt.hcl
that calls the module from step 1. terragrunt apply
- Done! 🎉
- AWS, this repo doesn't support any other IaaS provider at this time
- Terraform 0.12.4+
- Terragrunt v0.19.8+
- Support for Terraform Cloud Remote State (waiting on gruntwork-io/terragrunt#779)
- Examples for AWS Organizations/Multiple Accounts (see here https://github.com/gruntwork-io/terragrunt-infrastructure-live-example#how-is-the-code-in-this-repo-organized)
We welcome any and all contributions. Please create an Issue or a PR.
See LICENSE.md