A recipe to set up a good development environment to write terraform modules. Tested with Linux Ubuntu 24.04.1 LTS on WSL2 (should work with other Linux distros with some minor adaptations).
- Linux utils (wget, curl, jq, tar, unzip, git)
- tenv : https://github.com/tofuutils/tenv
- terraform CLI : https://developer.hashicorp.com/terraform/cli
- terraform-docs : https://github.com/terraform-docs/terraform-docs
- TFLint : https://github.com/terraform-linters/tflint
- Trivy : https://github.com/aquasecurity/trivy
- venv for Python3: https://docs.python.org/3/library/venv.html
- Pre-commit : https://pre-commit.com/
- Pre-commit-terraform : https://github.com/antonbabenko/pre-commit-terraform
- Checkov : https://github.com/bridgecrewio/checkov
- VSCode with terraform extensions : https://marketplace.visualstudio.com/items?itemName=4ops.terraform
Simplifies the management of multiple Terraform versions, ensuring compatibility with different projects.
TENV_LATEST=$(curl -s https://api.github.com/repos/tofuutils/tenv/releases/latest | jq -r '.assets[] | select(.name | endswith("Linux_x86_64.tar.gz")) | .browser_download_url')
curl -L -O $TENV_LATEST
mkdir ~/.tenv
tar xvzf $(echo $TENV_LATEST | grep -o -E "tenv_v.*") -C ~/.tenv
export PATH="$HOME/.tenv:$PATH"
tenv completion bash > ~/.tenv/tenv_completion.bash
echo -e '\n# tenv and terraform tools\nexport PATH="$HOME/.tenv:$PATH"\nsource $HOME/.tenv/tenv_completion.bash' >> ~/.bashrctenv terraform install
terraform -install-autocompleteAutomates the creation of files documenting inputs, outputs, resources, and dependencies in a Terraform module.
TDOC_LATEST=$(curl -s https://api.github.com/repos/terraform-docs/terraform-docs/releases/latest | jq -r '.assets[] | select(.name | endswith("linux-amd64.tar.gz")) | .browser_download_url')
curl -L -O $TDOC_LATEST
tar xzf $(echo $TDOC_LATEST | grep -o -E "terraform-docs-.+") -C ~/.tenv terraform-docs
terraform-docs completion bash > ~/.tenv/terraform-docs_completion.bash
echo -e '\nsource $HOME/.tenv/terraform-docs_completion.bash' >> ~/.bashrcEnsures best practices, identifies syntax errors, and enforces standards for Terraform configurations.
TFLINT_LATEST=$(curl -s https://api.github.com/repos/terraform-linters/tflint/releases/latest | jq -r '.assets[] | select(.name | endswith("tflint_linux_amd64.zip")) | .browser_download_url')
curl -L -O $TFLINT_LATEST
unzip -o $(echo $TFLINT_LATEST | grep -o -E "tflint_linux.+") -d ~/.tenvIdentifies security risks in container images, IaC files (including Terraform), and dependencies.
TRIVY_LATEST=$(curl -s https://api.github.com/repos/aquasecurity/trivy/releases/latest | jq -r '.assets[] | select(.name | endswith("Linux-64bit.tar.gz")) | .browser_download_url')
curl -L -O $TRIVY_LATEST
tar xzf $(echo $TRIVY_LATEST | grep -o -E "trivy_.+") -C ~/.tenv trivyEnsures consistent code quality by running checks (e.g., linting, formatting, security scans) before committing code to a repository.
sudo apt install python3.12-venv
python3 -m venv ~/.venv
source ~/.venv/bin/activate
pip install pre-commitDetects misconfigurations, security risks, and compliance violations in Terraform and other IaC templates.
pip install checkovTo develop terraform modules I use VSCode with Terraform extension by Anton Kulikov. It adds syntax support for the Terraform and Terragrunt configuration language.
Now that you installed all the devlopment supporting tools, its time to configure the terraform root module directory structure. A Standard Module Structure is presented in https://developer.hashicorp.com/terraform/language/modules/develop/structure . Look at the example bellow.
root-module/
├── README.md
├── main.tf
├── variables.tf
├── outputs.tf
├── providers.tf
├── modules/
│ ├── child-module-A/
│ │ ├── README.md
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ ├── outputs.tf
│ ├── child-module-B/
│ ├── .../
├── .pre-commit-config.yaml
└── .tflint.hcl
The .tflint.hcl file is the configuration file for TFLint. Its purpose is to define the rules, plugins, and configurations that TFLint will use when analyzing your Terraform code. This allows you to enforce best practices, identify issues, and customize the linter's behavior to fit your project requirements. The config that I use for terraform AWS resources is:
tflint {
required_version = "~> 0.54.0"
}
plugin "terraform" {
enabled = true
preset = "all"
}
plugin "aws" {
enabled = true
version = "0.36.0"
source = "github.com/terraform-linters/tflint-ruleset-aws"
deep_check = true
}
rule "aws_resource_missing_tags" {
enabled = true
tags = [
"env"
]
}The .pre-commit-config.yaml file is the configuration file for the Pre-commit framework. Its purpose is to define and manage pre-commit hooks, which are scripts that run automatically before a commit is made in a Git repository. These hooks ensure that code quality, consistency, and compliance checks are enforced.
repos:
- repo: https://github.com/antonbabenko/pre-commit-terraform
rev: v1.96.2
hooks:
- id: terraform_validate
- id: terraform_fmt
- id: terraform_tflint
args:
- --args=--config=__GIT_WORKING_DIR__/.tflint.hcl
- id: terraform_trivy
- id: terraform_checkov
name: "Terraform validate with Checkov"
args:
- --args=--quiet
- id: terraform_docs
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: detect-aws-credentials
name: "Pre-commit detect AWS credentials"
- id: detect-private-key
name: "Pre-commit detect private keys"
- id: end-of-file-fixer
name: "Pre-commit fix end of files"
- id: trailing-whitespace
name: "Pre-commit remove trailing whitespaces"
This template serves as a foundation for creating Terraform modules.
I developed a template to bootstrap the development of terraform modules to provision AWS resources. It help me to create an S3 bucket to store terraform state (with server-side encryption, versioning, lifecycle rules for noncurrent object transition and expiration, blocked of public access for enhanced security), and also creates a DynamoDB table for state locking.
# Use AWS CLI to configure the AWS Access Key ID and the AWS Secret Access Key for the user with the propper permission to provision the AWS resources.
aws configure
git clone https://github.com/zidenis/terraform-module-template-aws.git my-terraform-module
cd my-terraform-module
git remote remove origin
# Use this bash script to bootstrap the S3 bucket to hold the terraform state remotely
./backend_bootstrap.shNow the infrastructure is ready to start the development of your module. Use pre-commit to run the quality validations.
$ source ~/.venv/bin/activate
$ pre-commit run -a
[INFO] Initializing environment for https://github.com/antonbabenko/pre-commit-terraform.
[INFO] Initializing environment for https://github.com/pre-commit/pre-commit-hooks.
[INFO] Installing environment for https://github.com/pre-commit/pre-commit-hooks.
[INFO] Once installed this environment will be reused.
[INFO] This may take a few minutes...
Terraform validate.......................................................Passed
Terraform fmt............................................................Passed
Terraform validate with tflint...........................................Passed
Terraform validate with trivy............................................Passed
Terraform validate with Checkov..........................................Passed
Terraform docs...........................................................Passed
Pre-commit detect AWS credentials........................................Passed
Pre-commit detect private keys...........................................Passed
Pre-commit fix end of files..............................................Passed
Pre-commit remove trailing whitespaces...................................Passedrm $(echo $TENV_LATEST | grep -o -E "terraform-docs-.+")
rm $(echo $TENV_LATEST | grep -o -E "tenv_v.*")
rm $(echo $TFLINT_LATEST | grep -o -E "tflint_linux.+")
rm $(echo $TRIVY_LATEST | grep -o -E "trivy_.+")$ tenv version
tenv version v3.2.11
$ terraform version
Terraform v1.10.2
on linux_amd64
$ terraform-docs version
terraform-docs version v0.19.0 af31cc6 linux/amd64
$ tflint --version
TFLint version 0.54.0
+ ruleset.terraform (0.10.0-bundled)
$ trivy --version
Version: 0.58.0
$ pre-commit --version
pre-commit 4.0.1
$ checkov --version
3.2.334