Tools, Workflow, Security, Testing, CI/CD, Automation, AI Assistance, Governance, and Production Best Practices
Verified baseline: 5 September 2026
Audience: Terraform developers, DevOps/SRE, platform/cloud engineers, module authors, DevSecOps teams, and engineering leaders.
This handbook treats Terraform development as an engineering system, not a collection of unrelated commands. The goal is a fast local feedback loop, reproducible plans, secure authentication, reviewable changes, automated quality gates, policy enforcement, controlled production execution, and continuous drift/health feedback.
Executive standard
A strong default stack for a professional Terraform team is:
VS Code / Cursor / Claude Code
โ
HashiCorp Terraform Extension + terraform-ls
โ
Terraform MCP Server for current Registry/HCP context
โ
tenv
โ
Terraform CLI
โ
terraform fmt
terraform validate
terraform test
โ
TFLint
โ
Trivy
โ
terraform-docs
โ
Infracost
โ
pre-commit-terraform
โ
Git
โ
GitHub / GitLab
โ
CI quality gates + OIDC/workload identity
โ
HCP Terraform / Terraform Enterprise or another controlled runner
โ
Sentinel / OPA / Terraform Policy where appropriate
โ
Cloud infrastructure
โ
Post-deployment validation + drift/health monitoring
Tool classification
| Tool / capability | Default classification | Why |
|---|---|---|
| Terraform CLI | MUST HAVE | Core IaC engine |
| Git | MUST HAVE | Reviewable, auditable change history |
terraform fmt | MUST HAVE | Canonical formatting |
terraform validate | MUST HAVE | Configuration validity |
| Remote state + locking | MUST HAVE for teams | Prevents local-state drift and concurrent writes |
| Provider/module version constraints | MUST HAVE | Reproducibility |
.terraform.lock.hcl in Git | MUST HAVE for root configurations | Reproducible provider selection/checksums |
| VS Code + HashiCorp extension | STRONGLY RECOMMENDED | Fast authoring feedback |
terraform-ls | STRONGLY RECOMMENDED | IDE intelligence; usually bundled |
tenv | STRONGLY RECOMMENDED | Reproducible CLI versions |
| TFLint | STRONGLY RECOMMENDED | Terraform/provider-aware linting |
| Trivy | STRONGLY RECOMMENDED | IaC misconfiguration + optional secret scanning |
terraform test | STRONGLY RECOMMENDED | Native module/root tests |
terraform-docs | STRONGLY RECOMMENDED for modules | Prevents stale README interfaces |
pre-commit-terraform | STRONGLY RECOMMENDED | Cheap local automation |
| CI plan workflow | MUST HAVE for production teams | Reproducible review gate |
| OIDC/workload identity | MUST HAVE for CI cloud auth | Avoids static cloud credentials |
| Infracost | RECOMMENDED | PR-level cost feedback |
| Renovate | RECOMMENDED | Dependency hygiene |
| Terraform MCP Server | RECOMMENDED with AI coding | Current Registry/HCP context |
| Checkov | OPTIONAL / context dependent | Strong policy/compliance scanning; can overlap Trivy |
| Terratest | OPTIONAL | Real integration/E2E testing when native tests are insufficient |
| Terragrunt | OPTIONAL | Useful for large repeated multi-account/region layouts |
| Atlantis | OPTIONAL | PR-driven execution if it fits the operating model |
| HCP Terraform | RECOMMENDED / ENTERPRISE | Remote runs, state, governance, registry, RBAC |
| Terraform Enterprise | ENTERPRISE | Self-hosted HCP Terraform distribution |
| Sentinel / OPA | ENTERPRISE / governance | Policy gates |
| Conftest | OPTIONAL | Lightweight vendor-neutral Rego execution |
tfupdate | OPTIONAL / niche | Focused Terraform version rewriting; Renovate is broader |
2026-specific guidance
- Terraform MCP Server is now a first-class optionย for AI-assisted Terraform. Use it to ground an AI agent in current provider/module documentation instead of trusting model memory.
- Nativeย
terraform testย is the default first testing layer.ย Add Terratest when you truly need live system behavior, cross-service checks, retries, or non-Terraform assertions. - Trivy is the normal replacement for tfsecย in new workflows.
- For new S3 backends use native S3 state lockingย (
use_lockfile = true). Do not design a new backend around DynamoDB locking. - HCP Terraform policy choices are broader than Sentinel alone.ย OPA is supported and HashiCorp also has Terraform Policy in HCL; treat beta features cautiously.
- Terragrunt 1.x uses the streamlined CLI, e.g.ย
terragrunt run --all plan; oldยrun-allย examples should be considered legacy. - Do not build CI around static AWS/Azure/GCP keys.ย Use GitHub/GitLab OIDC or the cloud’s workload-identity mechanism.
PART 1 โ Terraform Development Ecosystem
1.1 The end-to-end model
Developer intent
โ
Editor / AI coding environment
โ
Language intelligence
โ
Version-controlled Terraform CLI
โ
Fast local quality gates
โ
Git change
โ
CI reproducibility gates
โ
Plan
โ
Security / cost / policy review
โ
Human approval
โ
Controlled apply
โ
Verification
โ
Drift / health feedback
Responsibility of each layer
| Layer | Responsibility | Typical tools |
|---|---|---|
| Editor | Write/navigate/refactor HCL | VS Code, Cursor |
| AI assistant | Boilerplate, explanation, refactoring | Claude Code, Cursor, VS Code AI |
| Language server | Schema-aware completion/diagnostics/navigation | terraform-ls |
| AI context server | Current Terraform Registry/HCP information | Terraform MCP Server |
| Version manager | Select project-approved binaries | tenv, mise, asdf, tfenv |
| Terraform engine | Init/plan/apply/state/test | Terraform CLI |
| Formatter | Canonical HCL style | terraform fmt |
| Validator | Terraform language/module validity | terraform validate |
| Linter | Terraform/provider best practices | TFLint |
| Security scanner | Misconfiguration/compliance/secret checks | Trivy, Checkov |
| Test layer | Behavior assertions | terraform test, Terratest |
| Documentation | Generate module interface docs | terraform-docs |
| Cost analysis | Estimate cost delta | Infracost |
| Commit automation | Run cheap checks before push | pre-commit / pre-commit-terraform |
| VCS | Review/audit | GitHub, GitLab |
| CI | Reproduce quality gates and create plan | GitHub Actions, GitLab CI |
| Remote runner/orchestrator | Controlled execution/state/governance | HCP Terraform, TFE, Atlantis |
| Policy as code | Organizational guardrails | Terraform Policy, Sentinel, OPA |
| Cloud | Actual infrastructure | AWS, Azure, GCP, SaaS providers |
Core principle: different tools answer different questions
fmt โ Is the code formatted?
validate โ Is the Terraform configuration structurally valid?
TFLint โ Is it suspicious, deprecated, inconsistent, or provider-invalid?
Trivy โ Is it insecure or dangerously configured?
test โ Does the module satisfy its intended behavior?
plan โ What will Terraform change in this real context?
Infracost โ What may the cost impact be?
Policy โ Is the change allowed by organizational rules?
Review โ Should we make this change?
Apply โ Execute the approved change.
Verify โ Did the system reach the expected state?
Code language: JavaScript (javascript)
No single tool replaces the others.
PART 2 โ Core Terraform Development Tools
2. Terraform CLI
What
Terraform CLI is the execution engine for Terraform configuration, dependency initialization, planning, applying, state operations, testing, and inspection.
Essential command map
| Command | Use it when | Production note |
|---|---|---|
terraform init | First run, provider/module/backend changes | Review lock-file changes |
terraform fmt | During authoring and before commit | Automate |
terraform validate | After editing modules/config | Does not validate live cloud behavior |
terraform plan | Before any change | Review replacements/destruction |
terraform apply | Execute an approved plan | Prefer controlled runner |
terraform destroy | Intentionally remove stack | High-risk; require strong controls |
terraform console | Test expressions/functions | Great for debugging locals/CIDR logic |
terraform output | Read root outputs | Avoid exposing sensitive values |
terraform show | Inspect state or saved plan | Plan/state can contain secrets |
terraform providers | Inspect provider dependencies | Useful for upgrade debugging |
terraform state | Controlled state inspection/moves | High-risk; use change procedure |
terraform import | Bring existing resources under management | Prefer reviewable import workflows |
terraform test | Execute .tftest.hcl tests | Default first test framework |
Practical workflow
terraform version
terraform init
terraform fmt -recursive
terraform validate
terraform test
terraform plan -out=tfplan
terraform show tfplan
<em># apply only after review/approval</em>
terraform apply tfplan
Code language: HTML, XML (xml)
terraform init
What it does:
- Initializes backend.
- Downloads providers.
- Downloads child modules.
- Creates/updatesย
.terraform.lock.hcl. - Prepares the working directory.
Useful patterns:
terraform init
terraform init -upgrade
terraform init -backend=false <em># useful for validation jobs that do not need state</em>
terraform init -reconfigure
Code language: HTML, XML (xml)
Use -upgrade deliberately, not on every CI run, because it tells Terraform to re-evaluate dependency selections.
terraform fmt
terraform fmt
terraform fmt -recursive
terraform fmt -check -recursive
Local development: run write mode.
CI: run -check so CI detects unformatted code without modifying the branch.
terraform validate
terraform init -backend=false
terraform validate
Code language: JavaScript (javascript)
Validates Terraform configuration consistency and syntax in an initialized directory. It does not prove:
- credentials are valid,
- resource values are allowed by the cloud API,
- IAM permissions are sufficient,
- deployment will succeed,
- architecture is secure,
- cost is acceptable.
Those require lint/security/plan/test/policy/runtime checks.
terraform plan
terraform plan
terraform plan -out=tfplan
terraform show -no-color tfplan
terraform show -json tfplan > tfplan.json
Review especially:
-/+ย replacements,- deletions,
- IAM changes,
- network exposure,
- encryption changes,
- database/storage replacement,
- identity-provider changes,
- state moves/imports,
- count/for_each key churn.
Do not treat “Plan: 1 to add, 0 to change, 0 to destroy” as sufficient review. The kind of resource matters.
terraform apply
Recommended hierarchy:
- HCP Terraform/TFE or controlled CI runner.
- Dedicated deployment runner with OIDC/workload identity.
- Laptop apply only for sandbox/learning or documented break-glass workflows.
Applying a saved reviewed plan is safer than regenerating a plan immediately before apply when your workflow supports preserving the plan artifact securely.
terraform destroy
Treat as a destructive privileged operation. Prefer environment protection, explicit approval, and resource protection where appropriate.
terraform show
Saved plan JSON is excellent input for policy engines and scanners:
terraform plan -out=tfplan
terraform show -json tfplan > tfplan.json
Security: plan output can contain sensitive information. Store it only in trusted, short-lived CI artifacts.
terraform state
Useful commands:
terraform state list
terraform state show aws_instance.web
terraform state mv OLD_ADDRESS NEW_ADDRESS
terraform state rm ADDRESS
Code language: CSS (css)
Policy:
- Never directly editย
terraform.tfstate. - Back up/retain remote state versions.
- Require peer review/change ticket for production state surgery.
- Prefer Terraform language mechanisms such asย
movedย blocks where they solve the problem cleanly. state rmย means “stop managing this object”; it does not delete the real object.
3. VS Code + HashiCorp Terraform Extension
Why
The editor should catch low-cost mistakes before you reach a terminal or CI.
The official HashiCorp extension currently provides language-server-backed:
- syntax highlighting,
- IntelliSense/completion,
- inline diagnostics,
- formatting,
- go-to-definition and symbols,
- module/project navigation,
- snippets,
- HCP Terraform workspace/run integration,
- support for newer Terraform language surfaces.
Installation
VS Code Marketplace extension:
HashiCorp Terraform
publisher: HashiCorp
The extension bundles a compatible terraform-ls, so most VS Code users should not separately install the language server.
Recommended settings
Example .vscode/settings.json:
{
"[terraform]": {
"editor.defaultFormatter": "HashiCorp.terraform",
"editor.formatOnSave": true,
"editor.formatOnPaste": false,
"editor.codeActionsOnSave": {
"source.organizeImports": "never"
}
},
"[terraform-vars]": {
"editor.defaultFormatter": "HashiCorp.terraform",
"editor.formatOnSave": true
},
"files.trimTrailingWhitespace": true,
"files.insertFinalNewline": true,
"editor.rulers": [100, 120]
}
Code language: JSON / JSON with Comments (json)
The HashiCorp extension should be the authority for Terraform formatting; avoid competing formatters for .tf.
Useful companion extensions
Keep the list small:
- GitLens or your organization’s Git review extension.
- YAML extension for CI/config files.
- Markdown lint/preview for module docs.
- EditorConfig if your organization uses it.
- AI assistant only if approved by your security/data policy.
Avoid installing multiple Terraform format/language extensions at the same time.
4. terraform-ls
What
terraform-ls is HashiCorp’s official Terraform language server. It exposes IDE features over the Language Server Protocol.
Provides
- completions,
- diagnostics,
- navigation,
- reference awareness,
- provider/schema intelligence,
- module awareness,
- workspace indexing.
Installation decision
VS Code
Do not normally install manually. The HashiCorp Terraform extension bundles the compatible server.
Other LSP-compatible editors
Manual installation can be appropriate.
macOS/Linux with Homebrew:
brew install hashicorp/tap/terraform-ls
terraform-ls version
Best practice
Open the project folder/workspace, not only one .tf file. Whole-project indexing enables better module/ref navigation.
5. Terraform MCP Server
What
Terraform MCP Server connects an MCP-capable AI client to current Terraform provider/module/policy information and, when configured, HCP Terraform/TFE context.
Problem it solves
Without external grounding, an AI model can produce:
- provider arguments removed two versions ago,
- fictional resources,
- invalid nesting,
- outdated module interfaces,
- obsolete HCP Terraform behavior.
MCP reduces that risk by giving the agent current source context.
Architecture
Developer request
โ
AI host / coding agent
โ
MCP client
โ
Terraform MCP Server
โ
Terraform Registry / HCP Terraform
โ
Current provider, module, policy, workspace context
โ
AI-generated suggestion
โ
fmt โ validate โ lint โ security โ test โ plan
Code language: JavaScript (javascript)
Use cases
- “Show the current schema for this AWS resource before generating it.”
- “Find an approved module in our private registry.”
- “Explain this provider argument using the current provider docs.”
- “Generate a module that is compatible with our pinned provider.”
- “Find the HCP Terraform workspace for this stack and summarize its run context.”
Example prompts
Using the Terraform MCP Server, verify the current AWS provider schema for
aws_s3_bucket and generate the smallest secure example compatible with our
required provider constraint. Do not invent attributes.
Code language: JavaScript (javascript)
Find the current Registry documentation for the module used in ./network.
Explain which inputs are required and identify any code in our wrapper that is
using removed/deprecated inputs. Do not change state addresses.
Code language: JavaScript (javascript)
Before modifying this Terraform, list the resources that would be security
sensitive (IAM, KMS, network ingress, state backend). Generate code only after
checking current provider documentation. Then run fmt/validate/test and explain
remaining assumptions.
Code language: JavaScript (javascript)
Security rules
Treat the MCP server as a privileged integration if it can access private HCP Terraform information.
- Scope HCP tokens minimally.
- Do not expose sensitive state to an AI tool by default.
- Separate read/documentation use from write/run-management permissions.
- Review generated commands before execution.
- Never authorize autonomous production apply merely because the generated HCL validates.
Recommendation: Strongly recommended for teams already using AI-assisted Terraform, optional otherwise.
PART 3 โ Terraform Version Management
6. tenv
What
tenv is a Go-based version manager for Terraform, OpenTofu, Terragrunt, Terramate, and Atmos. It is the successor to tfenv/tofuenv.
Why
One globally installed Terraform version creates avoidable problems:
- project A needs a new language feature,
- project B is still validated on an older minor version,
- CI and laptop silently differ,
- developers accidentally upgrade providers/state behavior by upgrading the CLI.
Installation
macOS:
brew install tofuutils/tap/tenv
Verify:
tenv --version
tenv tf --help
Common usage
tenv tf install 1.16.0
tenv tf use 1.16.0
terraform version
Code language: CSS (css)
Project file:
# .terraform-version
1.16.0
Code language: CSS (css)
tenv can also resolve compatible Terraform versions from required_version constraints.
Team policy
For root configurations:
terraform {
required_version = "~> 1.16.0"
}
Code language: JavaScript (javascript)
and use the same minor/patch policy in CI.
For reusable modules, avoid unnecessarily over-constraining callers. If the module only needs a feature introduced in 1.7:
terraform {
required_version = ">= 1.7.0"
}
Code language: JavaScript (javascript)
Comparison
| Tool | Best fit | Strength | Limitation |
|---|---|---|---|
tenv | Terraform/OpenTofu/Terragrunt-centric teams | Purpose-built, multi-IaC binary support | Another tool to standardize |
tfenv | Existing Terraform-only estates | Familiar and simple | tenv is its modern successor |
asdf | Polyglot toolchains | One manager for many ecosystems | Plugin lifecycle/UX |
mise | Modern polyglot developer environments | Fast, broad tooling and task support | Broader than Terraform-specific need |
Default recommendation: tenv for Terraform-centric teams; mise is an excellent choice if the organization already standardizes all developer tools through it.
PART 4 โ Terraform Code Quality
7. terraform fmt
Formatting is non-negotiable because it removes style arguments from review.
terraform fmt -recursive
terraform fmt -check -recursive
Local: write/fix.
CI: -check.
Do not build an internal HCL formatting standard that conflicts with terraform fmt.
8. terraform validate
Use it as a structural gate, not as a linter or security test.
CI-friendly:
terraform init -backend=false -input=false
terraform validate -no-color
Code language: JavaScript (javascript)
Use a real plan later when values/backend/provider runtime context matters.
9. TFLint
What
TFLint is a pluggable Terraform linter. Its built-in Terraform rules catch language-level issues, and cloud provider rulesets add checks that Terraform’s core validation cannot know.
Problems it solves
- deprecated HCL patterns,
- unused declarations,
- missing required provider/version constraints,
- unpinned Registry modules,
- invalid or discouraged provider-specific values,
- invalid instance types,
- organization naming conventions through configured/custom rules.
Installation
macOS:
brew install terraform-linters/tap/tflint
Windows:
winget install -e --id TerraformLinters.tflint
Code language: CSS (css)
Linux: use the signed/attested release artifacts or the project’s documented installer.
Production-oriented .tflint.hcl
tflint {
required_version = ">= 0.64.0"
}
config {
call_module_type = "all"
disabled_by_default = false
}
plugin "terraform" {
enabled = true
preset = "recommended"
}
plugin "aws" {
enabled = true
version = "0.48.0"
source = "github.com/terraform-linters/tflint-ruleset-aws"
}
# Useful team-level additions beyond the recommended preset.
rule "terraform_documented_variables" {
enabled = true
}
rule "terraform_documented_outputs" {
enabled = true
}
rule "terraform_naming_convention" {
enabled = true
}
Code language: PHP (php)
Initialize and run:
tflint --init
tflint --recursive --format=compact
For CI systems repeatedly running tflint --init, provide an authenticated GitHub token to avoid anonymous GitHub API rate limits.
TFLint vs validate
terraform validate | TFLint |
|---|---|
| Terraform-native structural validity | Static lint/best-practice checks |
| Understands Terraform language/module configuration | Extensible provider-specific rules |
| Not a style/security scanner | Can catch deprecated/invalid provider patterns |
| Mandatory baseline | Strongly recommended complement |
PART 5 โ Terraform Security
10. Trivy
What
Trivy scans Terraform/IaC for misconfiguration and can also scan repositories/filesystems for secrets and other security problems.
Common findings
- public exposure,
- weak encryption,
- risky IAM,
- permissive security groups,
- weak storage policies,
- Kubernetes misconfiguration,
- plaintext secret patterns.
Commands
IaC misconfiguration:
trivy config .
Block high/critical findings:
trivy config --severity HIGH,CRITICAL --exit-code 1 .
Code language: PHP (php)
Scan repository/filesystem for both misconfiguration and secrets:
trivy fs --scanners misconfig,secret --severity HIGH,CRITICAL .
Use tfvars when appropriate:
trivy config --tf-vars environments/staging/staging.tfvars .
Policy
- Run a fast high/critical gate locally.
- Run the authoritative scan in CI.
- Exceptions need a reason, owner, and preferably expiration date.
- Treat scanner output as a risk signal, not proof of exploitability.
11. Checkov
What
Checkov is an IaC static analysis and compliance/policy scanner with Terraform source and Terraform plan scanning.
Install in an isolated Python environment:
pipx install checkov
checkov --version
Source scan:
checkov -d .
Plan scan:
terraform plan -out=tfplan.binary
terraform show -json tfplan.binary > tfplan.json
checkov -f tfplan.json
Security: plan JSON may contain injected values and secrets. Create and scan it only in trusted CI and avoid publishing it as a broadly readable artifact.
Trivy vs Checkov
| Situation | Recommendation |
|---|---|
| Small/medium team wants one broad security tool | Trivy only |
| Organization already standardizes Prisma/Checkov policies/compliance | Checkov only can be enough |
| Regulated org has distinct, non-overlapping policy packs and accepts runtime cost | Both, but define ownership |
| Same findings duplicated in both with no governance benefit | Remove one |
Do not add both simply to create the appearance of more security.
PART 6 โ Terraform Testing
12. Native terraform test
What
Terraform’s native test framework executes .tftest.hcl files with run, variables, assertions, plan/apply modes, helper modules, and provider/resource mocking.
Minimal example
main.tf:
variable "environment" {
type = string
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "environment must be dev, staging, or prod"
}
}
locals {
name = "payments-${var.environment}"
}
output "name" {
description = "Generated workload name."
value = local.name
}
Code language: JavaScript (javascript)
tests/name.tftest.hcl:
run "staging_name" {
command = plan
variables {
environment = "staging"
}
assert {
condition = output.name == "payments-staging"
error_message = "Unexpected generated name."
}
}
Code language: JavaScript (javascript)
Run:
terraform test
terraform test -filter=tests/name.tftest.hcl
Provider mocking
For modules using real providers, Terraform 1.7+ can mock providers:
mock_provider "aws" {}
run "secure_bucket_configuration" {
command = plan
assert {
condition = aws_s3_bucket.example.bucket == var.bucket_name
error_message = "Bucket name wiring is incorrect."
}
}
Code language: JavaScript (javascript)
This is excellent for logic/interface tests without cloud credentials or real resources.
Test pyramid
Live E2E / integration
Terratest / custom tests
-----------------------------
terraform test
plan/apply + mocks/assertions
---------------------------------
validate + TFLint + security scan
-------------------------------------
fmt
What each layer proves
| Tool | Proves |
|---|---|
validate | Terraform configuration can be parsed/validated |
| TFLint | Lint/provider conventions |
terraform test | Declared module behavior/assertions |
Real plan | Concrete proposed change in target context |
| Terratest | Deployed infrastructure actually behaves as expected |
Terratest
Use when you need:
- actual AWS/Azure/GCP API behavior,
- HTTP/DNS/TLS checks,
- retries/eventual consistency,
- cross-component E2E validation,
- deploy โ validate โ destroy workflows.
Costs:
- slower,
- cloud cost,
- credential requirements,
- cleanup complexity,
- flaky external dependencies.
Default: native terraform test first; Terratest only for gaps.
Kitchen-Terraform
Still useful in teams already invested in Test Kitchen/Ruby-based infrastructure testing. It is rarely the first recommendation for a new Terraform-only test platform in 2026.
PART 7 โ Terraform Documentation
13. terraform-docs
What
Generates Terraform module documentation from source:
- requirements,
- providers,
- modules,
- resources,
- inputs,
- outputs.
Installation
macOS:
brew install terraform-docs
Usage
terraform-docs markdown table .
terraform-docs markdown table --output-file README.md --output-mode inject .
Code language: CSS (css)
README before
# VPC module
Creates a VPC.
Code language: PHP (php)
README with markers
# VPC module
Creates a VPC.
<!-- BEGIN<em>_TF_</em>DOCS -->
<!-- END<em>_TF_</em>DOCS -->
Code language: HTML, XML (xml)
After terraform-docs, the marker section contains generated Requirements, Providers, Inputs, Outputs, etc.
.terraform-docs.yml
formatter: "markdown table"
output:
file: "README.md"
mode: "inject"
template: |-
<!-- BEGIN_TF_DOCS -->
{{ .Content }}
<!-- END_TF_DOCS -->
sort:
enabled: true
by: "required"
settings:
anchor: true
default: true
description: true
escape: true
hide-empty: false
html: true
lockfile: true
read-comments: true
required: true
sensitive: true
type: true
Code language: HTML, XML (xml)
Best practice
Generated interface reference is not a replacement for authored documentation. A gold-standard module README has:
- purpose,
- architecture/behavior,
- security assumptions,
- usage example,
- generated inputs/outputs,
- upgrade notes,
- operational caveats.
PART 8 โ Terraform Cost Management
14. Infracost
What
Infracost estimates cloud cost and turns Terraform changes into a cost delta visible during review.
Workflow
Terraform change
โ
Plan/HCL analysis
โ
Infracost
โ
Monthly cost estimate + delta
โ
PR reviewer sees cost impact
โ
Budget / FinOps decision
CLI
infracost breakdown --path .
infracost breakdown --path . --format json --out-file infracost-base.json
infracost diff --path . --compare-to infracost-base.json
Code language: CSS (css)
It can also consume Terraform plan JSON when source parsing is not sufficient.
CI recommendation
For GitHub, prefer the vendor’s current GitHub App or modern diff/scan actions where allowed. Avoid building new integrations around legacy action patterns unless you need the lower-level CLI.
Policy
Cost estimation is advisory unless your organization has explicitly defined budgets/thresholds. A small cost increase may be correct; a zero-cost plan may still be dangerously destructive.
PART 9 โ Git Automation
15. pre-commit-terraform
Why high value
It moves deterministic checks left:
git commit
โ
fmt
โ
validate
โ
TFLint
โ
Trivy
โ
terraform-docs
โ
commit accepted
Installation
brew install pre-commit
<em># or</em>
pipx install pre-commit
pre-commit --version
Code language: HTML, XML (xml)
Production-ready .pre-commit-config.yaml
repos:
- repo: https://github.com/antonbabenko/pre-commit-terraform
rev: v1.108.1
hooks:
- id: terraform_fmt
- id: terraform_validate
args:
- --hook-config=--retry-once-with-cleanup=true
- id: terraform_tflint
- id: terraform_trivy
args:
- --args=--severity=HIGH,CRITICAL
- --args=--exit-code=1
- id: terraform_docs
Code language: JavaScript (javascript)
Enable:
pre-commit install
pre-commit run --all-files
Local vs CI split
Local
Run checks that are fast and deterministic:
- fmt,
- validate,
- TFLint,
- focused Trivy,
- docs.
CI
Re-run them authoritatively and add:
- full security policy,
terraform test,- target-context plan,
- Infracost,
- plan-policy checks,
- approval/apply rules.
Never rely solely on local hooks; users can skip them and environments differ.
PART 10 โ Terraform Project Structure
16. Recommended repository layout
For a moderate monorepo:
terraform/
โโโ modules/
โ โโโ vpc/
โ โ โโโ main.tf
โ โ โโโ variables.tf
โ โ โโโ outputs.tf
โ โ โโโ versions.tf
โ โ โโโ tests/
โ โ โโโ README.md
โ โโโ eks/
โ โโโ rds/
โ โโโ iam/
โ
โโโ environments/
โ โโโ development/
โ โโโ staging/
โ โโโ production/
โ
โโโ .github/
โ โโโ workflows/
โโโ .pre-commit-config.yaml
โโโ .tflint.hcl
โโโ renovate.json
โโโ README.md
Root module vs child module
Root module: deployment unit. Owns backend, environment composition, concrete provider constraints, and state.
Child/reusable module: abstraction with documented inputs/outputs. It should not normally own a backend or assume one environment/account.
Files
Recommended per module:
main.tf # primary resources/module calls
variables.tf # inputs
outputs.tf # outputs
versions.tf # Terraform/provider requirements
locals.tf # optional, when locals warrant separation
data.tf # optional
tests/ # native tests
README.md
Code language: PHP (php)
Split further by domain only when it improves readability; Terraform loads all .tf files in the directory together.
Environment separation
Prefer separate state per meaningful failure/ownership boundary:
production/network
production/cluster
production/database
production/app-platform
rather than one giant production state.
Reasons:
- smaller blast radius,
- simpler permissions,
- faster plan,
- clearer ownership,
- fewer unrelated lock conflicts.
Repository strategy
| Strategy | Pros | Cons | Best fit |
|---|---|---|---|
| Monorepo | Shared standards, atomic changes, discovery | CI/path complexity, repo scale | Central platform teams |
| Multi-repo by system | Strong ownership boundaries | Cross-repo upgrades harder | Independent teams |
| One repo per environment | Strong isolation | Duplication/drift risk | Strict org separation |
| One repo per reusable module | Independent versioning/release | Many repos | Mature internal module ecosystem |
There is no universal “one repo per environment” rule. Choose boundaries from ownership, release cadence, permissions, and blast radius.
PART 11 โ Terragrunt
17. Terragrunt
Why it exists
Terragrunt wraps Terraform/OpenTofu to reduce repetition and orchestrate many related root modules.
Common value:
- shared remote-state configuration,
- generated provider configuration,
- reusable environment/account configuration,
- dependency outputs,
- multi-account/multi-region layouts,
- ordered execution across units.
Current CLI model
Modern Terragrunt 1.x:
terragrunt plan
terragrunt apply
terragrunt run --all plan
terragrunt run --all apply
Do not teach new teams to standardize on legacy run-all.
Example
live/
โโโ root.hcl
โโโ dev/
โ โโโ vpc/terragrunt.hcl
โ โโโ app/terragrunt.hcl
โโโ prod/
โโโ vpc/terragrunt.hcl
โโโ app/terragrunt.hcl
root.hcl:
remote_state {
backend = "s3"
config = {
bucket = "example-terraform-state"
key = "${path_relative_to_include()}/terraform.tfstate"
region = "ap-northeast-1"
encrypt = true
use_lockfile = true
}
}
generate "provider" {
path = "provider.generated.tf"
if_exists = "overwrite_terragrunt"
contents = <<EOF
provider "aws" {
region = "ap-northeast-1"
}
EOF
}
Code language: JavaScript (javascript)
prod/app/terragrunt.hcl:
include "root" {
path = find_in_parent_folders("root.hcl")
}
terraform {
source = "../../../modules/app"
}
dependency "vpc" {
config_path = "../vpc"
}
inputs = {
vpc_id = dependency.vpc.outputs.vpc_id
}
Code language: PHP (php)
When Terragrunt is unnecessary
Do not add it when:
- you have a few simple root modules,
- HCP Terraform already removes the orchestration pain you were trying to solve,
- duplication is small and explicit,
- the team does not need multi-unit orchestration,
- introducing a second language/workflow would cost more than it saves.
Terraform alone is a valid production architecture.
PART 12 โ CI/CD
18. GitHub Actions
Pipeline architecture
Pull request
โ
checkout
โ
setup pinned Terraform
โ
fmt -check
โ
init -backend=false (static/test jobs)
โ
validate
โ
TFLint
โ
Trivy
โ
terraform test
โ
OIDC โ target read/plan role
โ
terraform init
โ
terraform plan
โ
Infracost / policy / review
Code language: JavaScript (javascript)
Apply should be a separate controlled phase, not an automatic side effect of every PR plan.
Example CI workflow
name: terraform-ci
on:
pull_request:
paths:
- "**/*.tf"
- "**/*.tfvars"
- "**/*.tftest.hcl"
- ".github/workflows/terraform-ci.yml"
permissions:
contents: read
jobs:
quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: "1.16.0"
terraform_wrapper: false
- name: Format
run: terraform fmt -check -recursive
- name: Init without backend
run: terraform init -backend=false -input=false
- name: Validate
run: terraform validate -no-color
- name: Setup TFLint
uses: terraform-linters/setup-tflint@v6
with:
tflint_version: "v0.64.0"
cache: true
- name: Init TFLint plugins
run: tflint --init
env:
GITHUB_TOKEN: ${{ github.token }}
- name: TFLint
run: tflint --recursive --format=compact
- name: Trivy IaC
uses: aquasecurity/trivy-action@master
with:
scan-type: config
scan-ref: .
severity: HIGH,CRITICAL
exit-code: "1"
- name: Terraform tests
run: terraform test
Code language: PHP (php)
Supply-chain hardening note
For a true enterprise workflow, pin reusable GitHub Actions to reviewed immutable commit SHAs or enforce an organization action allowlist. Major tags are easier to read in a handbook but are mutable references.
Plan job with AWS OIDC
plan:
needs: quality
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
environment: staging
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
with:
terraform_version: "1.16.0"
terraform_wrapper: false
- name: Authenticate to AWS using OIDC
uses: aws-actions/configure-aws-credentials@v6
with:
role-to-assume: arn:aws:iam::123456789012:role/terraform-staging-plan
aws-region: ap-northeast-1
- name: Init
working-directory: environments/staging
run: terraform init -input=false
- name: Plan
working-directory: environments/staging
run: terraform plan -input=false -no-color
OIDC design
Trust should be constrained by claims such as:
- organization/repository identity,
- environment,
- branch/tag,
- immutable repository/org IDs where supported.
The plan role and apply role should be separate when practical.
Apply model
Recommended:
PR merged to protected branch
โ
new plan in controlled execution context
โ
policy checks
โ
environment approval
โ
assume apply role using OIDC
โ
terraform apply
โ
verification
Code language: PHP (php)
Why re-plan after merge? The reviewed branch may no longer be identical to the final protected branch if multiple changes merged.
If your system securely preserves a reviewed saved plan and guarantees code/state identity, applying the preserved plan is also valid.
Secrets
Never store:
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
long-lived Azure client secrets
long-lived GCP service-account JSON
Code language: JavaScript (javascript)
when federation is available.
19. GitLab CI
Use the same gates:
validate โ lint โ security โ test โ plan โ policy โ approval โ apply
GitLab supports OIDC ID tokens for cloud federation. Modern GitLab uses ID tokens, not the removed legacy CI_JOB_JWT_V2.
Illustrative shape:
stages:
- quality
- plan
- apply
terraform-quality:
stage: quality
image: hashicorp/terraform:1.16.0
script:
- terraform fmt -check -recursive
- terraform init -backend=false -input=false
- terraform validate
- terraform test
terraform-plan:
stage: plan
id_tokens:
GITLAB_OIDC_TOKEN:
aud: sts.amazonaws.com
script:
- echo "Exchange GitLab OIDC token for short-lived cloud credentials"
- terraform init -input=false
- terraform plan -input=false
terraform-apply:
stage: apply
when: manual
rules:
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
script:
- terraform apply -input=false
Code language: PHP (php)
Exact AWS/Azure/GCP token-exchange steps should follow the current cloud/GitLab federation documentation and your organization’s role design.
PART 13 โ Atlantis
20. Atlantis
What
Atlantis is a server that reacts to pull-request comments/events and runs Terraform plans/applies in a PR-driven workflow.
PR opened
โ
Atlantis autoplan
โ
review plan
โ
approval
โ
atlantis apply
Commands
atlantis plan
atlantis apply
Strengths
- PR-native workflow,
- project/workspace awareness,
- locking,
- plan/apply conversation in VCS,
- works across multiple Terraform projects.
Atlantis locks a directory/workspace when a plan is active so competing PRs do not casually race the same deployment unit.
Atlantis vs GitHub Actions vs HCP Terraform
| Need | Better fit |
|---|---|
| Generic build/test ecosystem | GitHub/GitLab CI |
| Comment-driven Terraform workflow you operate | Atlantis |
| Managed state, remote runs, RBAC, registry, run tasks, policy, health | HCP Terraform |
| Self-hosted HCP feature set | Terraform Enterprise |
Avoid running Atlantis and a separate CI apply system against the same state without a very explicit ownership model.
PART 14 โ HCP Terraform
21. HCP Terraform
What it adds beyond CLI
- remote state and state history,
- stronger centralized run coordination,
- remote runs,
- workspaces,
- projects,
- variable sets,
- self-hosted agents,
- private module/provider registry,
- run tasks,
- policy enforcement,
- VCS-driven speculative plans,
- team/project/workspace RBAC,
- health assessments including drift detection and continuous validation,
- API/audit capabilities depending on edition.
Enterprise workflow
Git branch
โ
Pull request
โ
HCP speculative plan
โ
CI/security/cost checks
โ
review
โ
merge
โ
HCP run
โ
policy checks / run tasks
โ
approval
โ
remote worker or private agent
โ
cloud
โ
health assessment / drift detection
Code language: PHP (php)
Workspaces
An HCP Terraform workspace is a deployment/state boundary, not the same concept as a Terraform CLI workspace.
Use workspaces to separate infrastructure with different:
- state,
- permissions,
- ownership,
- credentials,
- run cadence,
- blast radius.
Avoid a single giant workspace for an entire company environment.
Projects
Use projects as access-control/organizational boundaries grouping workspaces and Stacks.
Good project boundaries:
- platform,
- analytics,
- security,
- business unit,
- account/portfolio.
Variable sets
Good uses:
- common non-secret environment settings,
- dynamic credential configuration,
- shared provider settings,
- organization/project-wide standards.
Do not use variable sets as an excuse to hide every important deployment value from code review.
Agents
Use HCP Terraform Agents when the run must reach:
- private VPC/VNet resources,
- on-premises services,
- private APIs,
- network-isolated providers.
Agents need only outbound connectivity to HCP Terraform.
Do not deploy agents merely because “enterprise teams use agents.” Built-in workers are simpler when private network access/custom tooling is not required.
Private registry
Use the private registry for:
- approved reusable modules,
- internally developed providers,
- versioned organization patterns.
A mature platform team should make the secure path the easy path:
developer need โ approved private module โ small set of inputs โ tests/policy โ deploy
Code language: JavaScript (javascript)
Run tasks
Useful for third-party checks at lifecycle stages such as:
- pre-plan,
- post-plan,
- pre-apply,
- post-apply.
Examples:
- security platform,
- cost governance,
- custom compliance,
- image validation.
Only integrate trusted run-task services because run-related information can be sensitive.
HCP Terraform vs Terraform Enterprise vs CLI
| Capability | Terraform CLI | HCP Terraform | Terraform Enterprise |
|---|---|---|---|
| Terraform engine | Yes | Yes | Yes |
| Local execution | Yes | Can integrate | Can integrate |
| Managed SaaS | No | Yes | No |
| Self-hosted platform | No | No | Yes |
| Remote state | Via backend | Built in | Built in |
| Remote runs | No platform by itself | Built in | Built in |
| Projects/RBAC | No | Yes | Yes |
| Private registry | No | Yes | Yes |
| Agents | N/A | Yes | Yes |
| Policy/run tasks | External | Integrated | Integrated |
| Drift/health | External | Integrated by edition | Integrated |
Terraform Enterprise is the self-hosted distribution of the HCP Terraform application for organizations requiring private hosting/advanced architecture/compliance controls.
PART 15 โ Policy as Code
22. Sentinel
What
HashiCorp’s policy-as-code framework integrated with HCP Terraform/TFE.
Enforcement styles
- Advisoryย โ report failure but allow run.
- Soft mandatory / overridableย โ block unless authorized override.
- Hard mandatory / mandatoryย โ block until fixed, subject to platform policy-set semantics.
Use terms carefully because HCP Terraform’s UI/framework-specific naming can differ.
Example policy scenarios
- approved AWS regions,
- no public storage,
- allowed EC2 families,
- mandatory tags,
- encryption required,
- restrict resource deletion,
- only approved modules.
Rollout model
new rule
โ
advisory
โ
observe false positives
โ
fix existing estate
โ
mandatory with controlled exception process
Code language: JavaScript (javascript)
Do not deploy dozens of untested hard-blocking policies on day one.
23. OPA / Conftest
OPA
OPA evaluates Rego policies against structured input. Terraform plan JSON is a common input:
terraform plan -out=tfplan
terraform show -json tfplan > tfplan.json
opa exec --decision terraform/analysis/authz --bundle policy/ tfplan.json
Caveat: plan-time unknown values can limit what a policy can know.
Conftest
Conftest is a convenient CLI for executing Rego checks against structured files.
conftest test tfplan.json --policy policy/
conftest verify --policy policy/
Typical policy:
package main
deny contains msg if {
some rc in input.resource_changes
rc.type == "aws_security_group_rule"
some cidr in rc.change.after.cidr_blocks
cidr == "0.0.0.0/0"
msg := sprintf("Public ingress is not allowed: %s", [rc.address])
}
Code language: JavaScript (javascript)
Production policies need careful handling for null/unknown/alternate resource shapes; the snippet is intentionally small.
Decision guide
| Framework | Best fit |
|---|---|
| Terraform Policy (HCL) | Terraform-centric HCP teams wanting native HCL policy; evaluate maturity while beta |
| Sentinel | HCP/TFE estates with HashiCorp governance investment |
| OPA | Vendor-neutral enterprise policy platform |
| Conftest | Lightweight local/CI Rego execution |
PART 16 โ Dependency Management
24. Renovate
What
Automates dependency update PRs for:
- Terraformย
required_version, .terraform-version,- providers,
- Registry modules,
- Git-based modules where supported,
- GitHub Actions,
- many surrounding build dependencies.
Recommended renovate.json
{
"extends": ["config:recommended"],
"labels": ["dependencies"],
"packageRules": [
{
"matchManagers": ["terraform", "terraform-version"],
"groupName": "terraform dependencies",
"schedule": ["before 6am on monday"]
},
{
"matchManagers": ["github-actions"],
"groupName": "github actions"
},
{
"matchUpdateTypes": ["major"],
"dependencyDashboardApproval": true
}
]
}
Code language: JSON / JSON with Comments (json)
Upgrade policy
Do not auto-merge major Terraform/provider/module upgrades into production infrastructure merely because CI is green.
Recommended:
patch โ may auto-merge after strong test gates
minor โ normal PR review
major โ explicit upgrade issue, changelog review, staged rollout
25. tfupdate
tfupdate is a focused utility for rewriting Terraform/OpenTofu core/provider/module version constraints and lock files.
Example:
tfupdate terraform -v 1.16.0 -r .
tfupdate provider aws -v "~> 6.0" -r .
Code language: CSS (css)
It is still useful for scripts and specialized bulk updates.
Default recommendation: prefer Renovate for continuous dependency management because it covers Terraform, modules, providers, actions, and many other dependencies with PR workflows. Use tfupdate when you specifically need command-line rewriting/automation.
PART 17 โ Terraform Console
26. terraform console
The console is one of the fastest ways to debug Terraform expressions without creating resources.
terraform console
Code language: JavaScript (javascript)
Examples:
> upper("prod")
"PROD"
> length(["a", "b", "c"])
3
> contains(["dev", "prod"], "prod")
true
> merge({a = 1}, {b = 2})
{
"a" = 1
"b" = 2
}
> [for x in ["api", "worker"] : "prod-${x}"]
[
"prod-api",
"prod-worker",
]
> { for x in ["api", "worker"] : x => upper(x) }
{
"api" = "API"
"worker" = "WORKER"
}
> cidrsubnet("10.0.0.0/16", 8, 1)
"10.0.1.0/24"
> try({a = 1}.b, "fallback")
"fallback"
Code language: JavaScript (javascript)
Use it to prototype:
forย expressions,- map merging,
- conditionals,
- CIDR subdivision,
- string transformations,
try/can,- regex,
- collection conversion.
Do not use console output as a substitute for a repeatable test when the expression matters to production behavior.
PART 18 โ IDE + AI Development Workflow
27. Modern AI-assisted workflow
Developer intent
โ
AI agent
โ
Terraform MCP / current provider docs
โ
Generate/refactor HCL
โ
terraform fmt
โ
terraform validate
โ
TFLint
โ
Trivy
โ
terraform test
โ
human review
โ
real plan
Good AI tasks
- generate boilerplate,
- explain resources,
- draft variables/outputs,
- create native tests,
- refactor repeated HCL,
- produce module documentation,
- identify likely missing validation,
- compare plan output,
- search current provider docs through MCP.
Never blindly trust AI for
- IAM,
- security-group/network exposure,
- KMS/key policy,
- destructive lifecycle changes,
- provider upgrade compatibility,
terraform stateย operations,- imports/moves without address review,
- production apply,
- secret handling,
- cost assumptions.
AI prompt template
Act as a senior Terraform reviewer.
Context:
- Terraform: <constraint>
- Provider: <source + constraint>
- Execution: <HCP Terraform / CI / local>
- Environment: <dev/stage/prod>
- State boundary: <description>
Task:
<requested change>
Before writing code:
1. Use current Terraform/provider documentation or Terraform MCP.
2. Identify security, state, replacement, and cost risks.
3. Preserve resource addresses unless a move is explicitly required.
4. Do not hardcode credentials/secrets.
5. Prefer OIDC/workload identity.
After writing code:
1. terraform fmt
2. terraform validate
3. TFLint
4. Trivy
5. terraform test
6. explain expected plan and anything requiring human verification.
Never run or recommend an unreviewed production apply.
Code language: HTML, XML (xml)
PART 19 โ Terraform Developer Daily Workflow
28. Daily workflow
- Pull latest code
git switch main git pull --ff-only - Select project tool version
tenv tf install terraform version - Create a branch
git switch -c feat/add-private-endpoint - Initialize
terraform init - Write/change Terraform
- Format
terraform fmt -recursive - Validate
terraform validate - Lint
tflint --init tflint --recursive - Security scan
trivy config --severity HIGH,CRITICAL --exit-code 1 . - Run tests
terraform test - Generate docs
terraform-docs markdown table --output-file README.md --output-mode inject . - Plan in a safe target context
terraform plan - Inspect cost delta
infracost breakdown --path . - Review your own diff
git diff git status - Commit
git add . git commit -m "feat: add private endpoint" - Pre-commit hooks execute
- Push
git push -u origin HEAD - CI reproduces checks and plan
- PR reviewย Reviewer checks security, replacement, blast radius, cost, test quality.
- Policy validation
- Controlled apply
- Post-deployment verificationย Check service health, metrics, logs, connectivity, and expected outputs.
- Drift/health feedbackย Operational system closes the loop.
PART 20 โ Complete Developer Toolchain Reference
29. Master reference
| Tool | Problem solved | Basic usage | Value | Limitation | Classification |
|---|---|---|---|---|---|
| Terraform CLI | IaC lifecycle | terraform plan | Core engine | Needs surrounding controls | MUST |
| VS Code | Authoring | open project | Productivity | Editor only | Recommended |
| HashiCorp extension | Terraform IDE | install extension | Completion/diagnostics | VS Code focused | Recommended |
terraform-ls | LSP intelligence | normally bundled | Schema/navigation | Not security/policy | Recommended |
| Terraform MCP | AI current context | configure MCP host | Reduces stale AI output | Trust/access design | Recommended with AI |
tenv | Binary versions | tenv tf use | Reproducibility | Extra dependency | Recommended |
terraform fmt | Style | fmt -recursive | Deterministic format | Not validation | MUST |
terraform validate | Config validity | validate | Cheap errors | Not provider runtime security | MUST |
| TFLint | Lint/provider checks | tflint --recursive | Higher code quality | Not full security | Recommended |
| Trivy | Misconfig/secrets | trivy config . | Broad security | Policy noise possible | Recommended |
| Checkov | Compliance/IaC policy | checkov -d . | Broad policy library | Overlap | Optional |
terraform test | Native behavior tests | terraform test | Fast/native | Live behavior may need more | Recommended |
| Terratest | Real integration tests | go test | Strong E2E | Slow/cost/flakiness | Optional |
| terraform-docs | Interface docs | terraform-docs ... | No stale input/output tables | Doesn’t write architecture narrative | Recommended |
| Infracost | Cost delta | infracost diff | FinOps in review | Estimate not invoice | Recommended |
| pre-commit-terraform | Local gates | pre-commit run | Fast feedback | Can be bypassed | Recommended |
| Git | Version/review | git diff | Audit/review | Needs policy | MUST |
| GitHub/GitLab | Collaboration | PR/MR | Review controls | Platform dependency | MUST for teams |
| GitHub Actions/GitLab CI | Automation | pipeline | Reproducible checks | Runner/security design needed | MUST for prod teams |
| Terragrunt | Multi-unit DRY/orchestration | run --all plan | Scale multi-env layouts | Added abstraction | Optional |
| Atlantis | PR-driven Terraform | PR commands | Terraform-focused UX | Operate server/security | Optional |
| HCP Terraform | Remote Terraform platform | workspace runs | State/runs/RBAC/policy | Commercial/platform choice | Recommended/Enterprise |
| Terraform Enterprise | Self-hosted HCP | self-host | Compliance/private hosting | Operational burden | Enterprise |
| Sentinel | HCP/TFE policy | policy sets | Integrated governance | HashiCorp-specific | Enterprise |
| OPA | Vendor-neutral policy | opa exec | Reusable policy platform | Rego learning curve | Enterprise/Optional |
| Conftest | Rego CLI | conftest test | Easy CI integration | Not Terraform orchestrator | Optional |
| Renovate | Dependency PRs | bot/app | Sustainable upgrades | Needs grouping/rules | Recommended |
tfupdate | Constraint rewrites | tfupdate provider | Focused automation | Narrower than Renovate | Optional |
PART 21 โ Recommended Stacks by Maturity
30. Beginner
Terraform CLI
VS Code
HashiCorp Terraform Extension
terraform fmt
terraform validate
Git
Add a remote backend once working with others.
31. Professional developer
Terraform CLI
VS Code + terraform-ls
tenv
TFLint
Trivy
terraform test
terraform-docs
pre-commit-terraform
GitHub/GitLab CI
remote state + locking
OIDC
32. Senior / Platform engineer
Everything above
Terraform MCP Server
Infracost
reusable module standards
Renovate
structured state boundaries
policy tests
controlled runners
HCP Terraform where appropriate
Terragrunt only if complexity justifies it
Code language: JavaScript (javascript)
33. Enterprise platform
approved IDE/toolchain
private module/provider registry
central CI templates
OIDC/workload identity
remote execution
HCP Terraform/TFE
private agents where needed
RBAC
run tasks
policy-as-code
cost governance
audit logs
drift/health assessments
dependency automation
AI/MCP governance
Code language: PHP (php)
PART 22 โ Gold Standard Terraform Pipeline
34. Pipeline
Developer
โ
IDE
โ
AI/MCP assistance
โ
Terraform code
โ
Format
โ
Validate
โ
Lint
โ
Security scan
โ
Native tests
โ
Documentation
โ
Pre-commit
โ
Push
โ
CI reproduces gates
โ
OIDC authentication
โ
Terraform plan
โ
Cost analysis
โ
Policy validation
โ
Code review
โ
Approval
โ
Controlled apply
โ
Post-deploy verification
โ
Monitoring / drift / continuous validation
Quality gates
| Gate | Failure means |
|---|---|
| Format | Code not canonical |
| Validate | Terraform config invalid |
| TFLint | Quality/provider rule violation |
| Security | Risk exceeds accepted threshold |
| Test | Contract/behavior regression |
| Docs | Module API reference stale |
| Plan | Change differs from developer intent |
| Cost | Material unexpected spend |
| Policy | Organization rule violated |
| Review | Human risk/architecture concerns |
| Approval | Production change not authorized |
| Verify | Deployment outcome not healthy |
PART 23 โ Local Development Setup
35. macOS
Homebrew-centered setup:
brew tap hashicorp/tap
brew install hashicorp/tap/terraform
brew install hashicorp/tap/terraform-ls
brew install tofuutils/tap/tenv
brew install terraform-linters/tap/tflint
brew install trivy
brew install terraform-docs
brew install infracost
brew install pre-commit
brew install opa
brew install conftest
For Checkov:
brew install pipx
pipx ensurepath
pipx install checkov
You may omit manual terraform-ls if VS Code’s HashiCorp extension is your only LSP client.
Verify:
terraform version
tenv --version
tflint --version
trivy --version
terraform-docs --version
infracost --version
pre-commit --version
opa version
conftest --version
checkov --version
36. Linux
Prefer official/vendor repositories or verified release artifacts rather than random curl-pipe-shell snippets.
Example base packages:
sudo apt-get update
sudo apt-get install -y git curl unzip jq pipx
Code language: JavaScript (javascript)
Then install:
- Terraform from HashiCorp’s official package repository,
- TFLint from verified GitHub release artifacts,
- Trivy from Aqua’s official package repository,
terraform-docs,ยtenv, OPA, Conftest from official releases,- Checkov withย
pipx install checkov, - pre-commit with OS package manager or pipx.
Keep installation logic in a reproducible developer bootstrap script or dev-container image.
37. Windows
Good choices:
wingetย where the project publishes a verified package,- Chocolatey in organizations already managing it,
- official signed release archives.
Known example:
winget install -e --id TerraformLinters.tflint
Code language: CSS (css)
Terraform itself can be installed via your organization’s package-management standard or HashiCorp’s official release archive.
Prefer WSL only if your team’s Terraform workflow intentionally standardizes on Linux semantics; do not require it just because Terraform can run there.
Setup checklist
[ ] Git
[ ] Terraform version manager
[ ] Pinned Terraform
[ ] Editor + HashiCorp Terraform extension
[ ] TFLint
[ ] Trivy
[ ] terraform-docs
[ ] pre-commit
[ ] Infracost if used
[ ] Checkov if selected
[ ] OPA/Conftest if selected
[ ] Cloud CLI
[ ] SSO/OIDC-compatible developer authentication
[ ] No long-lived cloud key in shell profile
[ ] Project hooks installed
PART 24 โ Sample Real AWS Project
38. Directory
aws-web/
โโโ backend.tf
โโโ versions.tf
โโโ provider.tf
โโโ variables.tf
โโโ main.tf
โโโ outputs.tf
โโโ terraform.tfvars.example
โโโ backend.hcl.example
โโโ tests/
โ โโโ basic.tftest.hcl
โโโ .tflint.hcl
โโโ .terraform-docs.yml
โโโ .pre-commit-config.yaml
โโโ .gitignore
โโโ README.md
versions.tf
terraform {
required_version = "~> 1.16.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 6.0"
}
}
}
Code language: JavaScript (javascript)
backend.tf
terraform {
backend "s3" {}
}
Code language: JavaScript (javascript)
backend.hcl.example
bucket = "REPLACE-ME-terraform-state"
key = "examples/aws-web/terraform.tfstate"
region = "ap-northeast-1"
encrypt = true
use_lockfile = true
Code language: JavaScript (javascript)
Initialize:
cp backend.hcl.example backend.hcl
<em># edit backend.hcl for your non-secret account settings</em>
terraform init -backend-config=backend.hcl
Code language: HTML, XML (xml)
Do not put access keys in backend config.
provider.tf
provider "aws" {
region = var.aws_region
default_tags {
tags = {
ManagedBy = "Terraform"
Project = var.project_name
Environment = var.environment
}
}
}
Code language: JavaScript (javascript)
Authentication comes from the AWS SDK credential chain: SSO/profile locally, OIDC/workload identity in CI.
variables.tf
variable "aws_region" {
description = "AWS region for this deployment."
type = string
default = "ap-northeast-1"
}
variable "project_name" {
description = "Short project identifier."
type = string
default = "tf-web"
}
variable "environment" {
description = "Deployment environment."
type = string
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "environment must be dev, staging, or prod."
}
}
variable "vpc_cidr" {
description = "CIDR for the VPC."
type = string
default = "10.42.0.0/16"
}
variable "azs" {
description = "Availability Zones for public subnets."
type = list(string)
default = ["ap-northeast-1a", "ap-northeast-1c"]
validation {
condition = length(var.azs) == 2
error_message = "This example expects exactly two AZs."
}
}
variable "public_subnet_cidrs" {
description = "CIDRs for public subnets, one per AZ."
type = list(string)
default = ["10.42.1.0/24", "10.42.2.0/24"]
validation {
condition = length(var.public_subnet_cidrs) == 2
error_message = "This example expects exactly two public subnet CIDRs."
}
}
variable "ami_id" {
description = "Approved AMI ID for the EC2 instance."
type = string
}
variable "instance_type" {
description = "EC2 instance type."
type = string
default = "t3.micro"
}
variable "allowed_http_cidrs" {
description = "CIDRs permitted to access TCP/80. Do not use 0.0.0.0/0 unless public exposure is intended and approved."
type = list(string)
}
Code language: PHP (php)
main.tf
locals {
subnet_map = {
for idx, az in var.azs :
az => var.public_subnet_cidrs[idx]
}
}
resource "aws_vpc" "this" {
cidr_block = var.vpc_cidr
enable_dns_support = true
enable_dns_hostnames = true
tags = {
Name = "${var.project_name}-${var.environment}"
}
}
resource "aws_internet_gateway" "this" {
vpc_id = aws_vpc.this.id
tags = {
Name = "${var.project_name}-${var.environment}"
}
}
resource "aws_subnet" "public" {
for_each = local.subnet_map
vpc_id = aws_vpc.this.id
availability_zone = each.key
cidr_block = each.value
map_public_ip_on_launch = true
tags = {
Name = "${var.project_name}-${var.environment}-${each.key}"
}
}
resource "aws_route_table" "public" {
vpc_id = aws_vpc.this.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.this.id
}
tags = {
Name = "${var.project_name}-${var.environment}-public"
}
}
resource "aws_route_table_association" "public" {
for_each = aws_subnet.public
subnet_id = each.value.id
route_table_id = aws_route_table.public.id
}
resource "aws_security_group" "web" {
name_prefix = "${var.project_name}-${var.environment}-web-"
description = "HTTP access for example web instance"
vpc_id = aws_vpc.this.id
ingress {
description = "Approved HTTP clients"
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = var.allowed_http_cidrs
}
egress {
description = "Outbound access"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_instance" "web" {
ami = var.ami_id
instance_type = var.instance_type
subnet_id = values(aws_subnet.public)[0].id
vpc_security_group_ids = [aws_security_group.web.id]
associate_public_ip_address = true
metadata_options {
http_endpoint = "enabled"
http_tokens = "required"
}
root_block_device {
encrypted = true
}
tags = {
Name = "${var.project_name}-${var.environment}-web"
}
}
Code language: PHP (php)
This deliberately exposes no SSH port. In a production design, use SSM/session tooling or another approved administration path rather than opening port 22 globally.
outputs.tf
output "vpc_id" {
description = "VPC ID."
value = aws_vpc.this.id
}
output "public_subnet_ids" {
description = "Public subnet IDs keyed by availability zone."
value = { for az, subnet in aws_subnet.public : az => subnet.id }
}
output "instance_id" {
description = "EC2 instance ID."
value = aws_instance.web.id
}
output "public_ip" {
description = "Public IPv4 address of the example instance."
value = aws_instance.web.public_ip
}
Code language: JavaScript (javascript)
terraform.tfvars.example
environment = "dev"
ami_id = "ami-REPLACE-WITH-AN-APPROVED-AMI"
allowed_http_cidrs = ["203.0.113.0/24"]
Code language: JavaScript (javascript)
tests/basic.tftest.hcl
mock_provider "aws" {}
run "basic_plan" {
command = plan
variables {
environment = "dev"
ami_id = "ami-0123456789abcdef0"
allowed_http_cidrs = ["203.0.113.0/24"]
}
assert {
condition = aws_vpc.this.cidr_block == "10.42.0.0/16"
error_message = "Unexpected VPC CIDR."
}
assert {
condition = length(aws_subnet.public) == 2
error_message = "Expected two public subnets."
}
assert {
condition = aws_instance.web.metadata_options[0].http_tokens == "required"
error_message = "IMDSv2 must be required."
}
assert {
condition = aws_instance.web.root_block_device[0].encrypted == true
error_message = "Root volume must be encrypted."
}
}
Code language: PHP (php)
.gitignore
.terraform/
*.tfstate
*.tfstate.*
*.tfplan
tfplan*
crash.log
crash.*.log
override.tf
override.tf.json
*_override.tf
*_override.tf.json
backend.hcl
*.auto.tfvars
Do commit:
.terraform.lock.hcl
Terraform source
non-secret examples
tests
tool configuration
Code language: CSS (css)
Run locally
terraform init -backend=false
terraform fmt -recursive
terraform validate
tflint --init
tflint --recursive
trivy config --severity HIGH,CRITICAL .
terraform test
Code language: JavaScript (javascript)
For a real plan, authenticate through AWS SSO/profile and initialize the real backend:
terraform init -backend-config=backend.hcl
terraform plan -var-file=terraform.tfvars
Code language: JavaScript (javascript)
PART 25 โ Common Developer Mistakes
39. Mistakes and correct alternatives
| Mistake | Why dangerous | Correct alternative |
|---|---|---|
| Hardcoded cloud keys | Credential leak/rotation burden | OIDC, SSO, workload identity |
| Hardcoded secrets | HCL/plan/state leak | Secret manager + ephemeral/write-only features where provider supports |
Commit .tfstate | Secrets + no safe state locking | Remote state |
Commit .terraform/ | Large, platform-specific, unreviewable | Re-run init |
Ignore .terraform.lock.hcl | Provider drift | Commit root lock file |
| No provider constraints | Unexpected upgrades | Declare constraints |
| No module versions | Module drift | Pin Registry module versions |
| Apply from laptops | Weak audit/reproducibility | Controlled runner |
| No review | High blast radius | Protected PR flow |
| No lint/security tests | Preventable defects | Automated gates |
| One giant state | Huge blast radius/lock contention | Decompose by ownership/failure boundary |
| Overuse CLI workspaces | Hidden environment coupling | Separate roots/states/workspaces where environments differ |
| Huge root module | Slow/unowned/unreviewable | Compose smaller deployment units |
| Copy/paste infrastructure | Drift | Reusable modules/templates where repetition is stable |
| Weak variable design | Invalid combinations | Types, validation, object schemas |
Excessive -target | Partial graph surprises | Normal full plan/apply; use target for exceptional recovery |
| Direct state edits | Corruption | Terraform state/moved/import mechanisms |
Casual state rm | Terraform loses management | Controlled state procedure |
| Blind AI-generated code | Hallucination/security bugs | MCP/docs + automated gates + review |
| Ignore cost | Surprise spend | Infracost/FinOps review |
| Auto-apply PRs to prod | Unreviewed change | Merge + protected approval |
| Long-lived CI credentials | High-value secret | OIDC federation |
PART 26 โ Security Best Practices
40. Security checklist
Identity
[ ] No hardcoded cloud credentials
[ ] CI uses OIDC/workload identity
[ ] Developer auth uses SSO/short-lived credentials
[ ] Plan and apply roles follow least privilege
[ ] Production permissions separated from non-production
State
[ ] State is remote
[ ] State is encrypted
[ ] State access is restricted
[ ] State locking enabled
[ ] State versioning/history enabled where supported
[ ] State access/audit is monitored
[ ] State never committed to Git
Code/dependencies
[ ] Terraform version constrained
[ ] Providers constrained
[ ] .terraform.lock.hcl committed for root configurations
[ ] Modules explicitly versioned
[ ] Dependency updates automated but reviewed
[ ] No secrets in tfvars/source
Review
[ ] Branch protection enabled
[ ] Required reviewers defined
[ ] Security scan required
[ ] Tests required
[ ] Plan required
[ ] Destruction/replacement explicitly reviewed
[ ] Production approval protected
Runtime
[ ] Policy-as-code for critical invariants where justified
[ ] Audit logs retained
[ ] Drift/health monitoring enabled
[ ] Break-glass process documented
Code language: PHP (php)
State is a security asset
Terraform state may contain:
- database passwords,
- generated tokens,
- private endpoint metadata,
- identifiers,
- provider-returned secrets.
Marking an output sensitive = true primarily controls display; it does not magically remove the value from all state.
Prefer Terraform/provider features that avoid persistence when possible, including ephemeral values and write-only arguments where supported.
PART 27 โ Terraform Code Review Checklist
41. PR checklist
Intent
[ ] Ticket/goal is clear
[ ] Change is minimal for the intended outcome
[ ] Correct environment/account/region is targeted
Code quality
[ ] terraform fmt passes
[ ] terraform validate passes
[ ] TFLint passes
[ ] Naming is consistent
[ ] Variables are typed and validated
[ ] Inputs/outputs are documented
[ ] No unnecessary abstraction
Dependencies
[ ] Terraform constraint appropriate
[ ] Provider constraints appropriate
[ ] Lock-file changes expected
[ ] Reusable module versions pinned
[ ] Major dependency upgrades reviewed separately
Code language: CSS (css)
Security
[ ] No credentials/secrets
[ ] IAM is least privilege
[ ] No accidental 0.0.0.0/0 or ::/0
[ ] Encryption settings correct
[ ] Security scanner result reviewed
[ ] State/backend permissions unaffected or intentionally changed
Plan/blast radius
[ ] Adds/changes/destroys match intent
[ ] Every replacement (`-/+`) understood
[ ] Database/storage replacement scrutinized
[ ] IAM/KMS/networking changes scrutinized
[ ] for_each/count key changes understood
[ ] Moved/imported resource addresses correct
[ ] No unexpected state churn
Code language: JavaScript (javascript)
Reliability/cost
[ ] HA assumptions still valid
[ ] Capacity/quotas considered
[ ] Cost delta acceptable
[ ] Tests cover important behavior
[ ] Rollback/recovery approach understood
Documentation/operations
[ ] terraform-docs output current
[ ] README/runbook updated if behavior changed
[ ] Monitoring/alerts adjusted if needed
[ ] Post-deploy verification defined
PART 28 โ Terraform Productivity Best Practices
42. Reduce developer time without lowering safety
1. Standard repository template
Pre-create:
versions.tf
variables.tf
outputs.tf
tests/
.tflint.hcl
.terraform-docs.yml
.pre-commit-config.yaml
CI workflow
Renovate config
README markers
2. Reusable modules, but not “module everything”
Create a module when you have:
- repeated stable pattern,
- meaningful abstraction,
- security defaults worth centralizing,
- clear consumer interface.
Do not wrap one resource in a module merely to claim standardization.
3. Fast local path
Target:
fmt + validate + lint + focused security + mock tests
in a developer-friendly feedback loop.
Put slow live integration tests in CI/nightly pipelines.
4. Pre-approved module catalog
Make secure defaults easy:
Need private S3 bucket
โ
approved module
โ
3โ5 meaningful inputs
โ
encryption/logging/policy defaults already included
Code language: JavaScript (javascript)
5. Central CI templates
Do not copy 100 slightly different Terraform workflows. Provide versioned reusable CI workflows/components.
6. Automated documentation
Generated docs prevent “variable exists in code but not README.”
7. Automated dependency updates
Small continuous upgrades are usually safer than a two-year provider jump.
8. Cost feedback in PRs
Shift cost discussion before apply.
9. Remote execution
A consistent execution environment eliminates “worked on my laptop” differences and improves auditability.
10. Use AI for mechanical work
AI is excellent at:
- repetitive HCL,
- tests,
- docs,
- refactors.
Humans remain accountable for:
- intent,
- architecture,
- security,
- blast radius,
- production approval.
PART 29 โ Tool Overlap and Decision Guide
43. Overlap matrix
terraform validate vs TFLint
Use both. They answer different questions.
Trivy vs Checkov
Start with one. Add the second only for distinct policies/compliance.
Sentinel vs OPA
- HCP-first, integrated governance: Sentinel is natural.
- Cross-platform policy strategy: OPA is natural.
- HCP Terraform can support OPA too.
- Consider Terraform Policy as it matures if HCL-native policy is attractive.
tfenv vs tenv
For new Terraform-centric standardization, choose tenv unless existing tfenv investment outweighs migration benefit.
Terraform vs Terragrunt
Start with Terraform. Add Terragrunt to solve actual repetition/orchestration pain.
GitHub Actions vs Atlantis
- CI ecosystem + custom workflows: GitHub Actions.
- Terraform-specific PR command workflow: Atlantis.
- You can combine them if responsibilities are unambiguous: CI validates, Atlantis owns plan/apply.
Atlantis vs HCP Terraform
HCP Terraform is a broader platform: state, runs, RBAC, registry, agents, policy, health. Atlantis is a focused PR automation server.
terraform test vs Terratest
Start native. Add Terratest for real behavioral integration.
terraform-docs vs manual README
Use both:
Manual sections โ why/how/architecture
Generated section โ exact interface reference
Code language: PHP (php)
pre-commit vs CI
Use both:
pre-commit = developer speed
CI = enforcement
PART 30 โ Final Gold Standard Recommendation
44. Final stack
MUST HAVE
Terraform CLI
Git
terraform fmt
terraform validate
version constraints
.terraform.lock.hcl for root configs
remote state + locking for teams
code review
CI for production
OIDC/workload identity
plan review
STRONGLY RECOMMENDED
VS Code + HashiCorp Terraform Extension
terraform-ls
tenv
TFLint
Trivy
terraform test
terraform-docs
pre-commit-terraform
Infracost
Renovate
standard repository templates
reusable CI templates
post-deployment verification
OPTIONAL
Terraform MCP Server (recommended if AI is used)
Checkov
Terratest
Terragrunt
Atlantis
Conftest
tfupdate
ENTERPRISE / PLATFORM
HCP Terraform
Terraform Enterprise
private module/provider registry
private agents
RBAC
run tasks
policy sets
Sentinel / OPA / Terraform Policy
audit logging
drift detection / continuous validation
central cost/security governance
Code language: PHP (php)
Terraform Developer GOLD Standard Checklist Before Merge
SCOPE
[ ] I can explain exactly what this PR changes and why.
[ ] I changed only the intended state boundary/environment.
CODE
[ ] terraform fmt -check passes.
[ ] terraform validate passes.
[ ] TFLint passes.
[ ] No duplicate/copy-paste architecture was introduced unnecessarily.
[ ] Variables are typed, described, and validated where useful.
[ ] Outputs are intentional and documented.
VERSIONS
[ ] Terraform version policy is satisfied.
[ ] Provider constraints are explicit.
[ ] .terraform.lock.hcl changes are expected and reviewed.
[ ] Registry module versions are explicit.
SECURITY
[ ] No cloud credentials, passwords, API keys, tokens, or private keys are committed.
[ ] CI uses OIDC/workload identity.
[ ] Trivy/selected IaC security scan passes or exceptions are approved.
[ ] IAM follows least privilege.
[ ] Public ingress/egress is intentional.
[ ] Encryption is enabled where required.
[ ] State remains protected.
TESTING
[ ] terraform test passes.
[ ] Important module behavior is asserted.
[ ] Live integration testing is added when native tests cannot prove the requirement.
PLAN
[ ] A plan exists for the correct target.
[ ] I reviewed additions, changes, deletions, and replacements.
[ ] I understand every destructive/replacement action.
[ ] Resource-address changes are intentional.
[ ] No unexpected IAM/KMS/network/database changes exist.
[ ] Blast radius is acceptable.
COST
[ ] Cost delta has been reviewed when material.
[ ] New always-on/large resources are intentional.
DOCS
[ ] terraform-docs output is current.
[ ] Architecture/runbooks are updated if behavior changed.
DEPLOYMENT
[ ] Apply will run from the approved controlled environment.
[ ] Production approval requirements are met.
[ ] Rollback/recovery is understood.
[ ] Post-deployment verification is defined.
AFTER
[ ] Monitoring/alerts will detect regressions.
[ ] Drift/continuous validation is enabled where appropriate.
Code language: JavaScript (javascript)
Opinionated reference architecture
For most modern platform teams, the cleanest production model is:
Developer laptop
โโ SSO / short-lived local cloud auth
โโ VS Code + HashiCorp extension
โโ tenv
โโ fmt / validate / TFLint / Trivy / terraform test
โโ pre-commit
โ
Protected Git repository
โ
CI
โโ reproduce local checks
โโ dependency/supply-chain controls
โโ OIDC
โโ speculative/real plan
โโ cost/security feedback
โ
HCP Terraform / TFE or dedicated controlled execution
โโ remote state
โโ locking
โโ RBAC
โโ private agents only when network access requires them
โโ run tasks
โโ policy
โโ approvals
โ
Cloud
โ
Verification + observability + drift/health
Code language: PHP (php)
This is intentionally boring. Boring infrastructure delivery is good: deterministic, reviewable, repeatable, auditable, and difficult to bypass accidentally.
Source and currency notes
This handbook was checked against current vendor/project documentation available on 5 September 2026, including:
- HashiCorp Terraform CLI, testing, state, backend, policy, MCP Server, HCP Terraform, and Terraform Enterprise documentation.
- HashiCorp Terraform VS Code extension andย
terraform-ls. - tofuutilsย
tenv. - terraform-linters TFLint and AWS ruleset.
- Aqua Security Trivy.
- Checkov.
- terraform-docs.
- Infracost.
- antonbabenko/pre-commit-terraform.
- Gruntwork Terragrunt and Terratest.
- Atlantis.
- Open Policy Agent and Conftest.
- Renovate.
tfupdate.- GitHub Actions / AWS OIDC and GitLab OIDC documentation.
Selected official/reference URLs:
https://developer.hashicorp.com/terraform/
https://developer.hashicorp.com/terraform/mcp-server
https://developer.hashicorp.com/terraform/cloud-docs
https://developer.hashicorp.com/terraform/enterprise
https://marketplace.visualstudio.com/items?itemName=HashiCorp.terraform
https://github.com/hashicorp/terraform-ls
https://github.com/tofuutils/tenv
https://github.com/terraform-linters/tflint
https://trivy.dev/
https://www.checkov.io/
https://terraform-docs.io/
https://www.infracost.io/docs/
https://github.com/antonbabenko/pre-commit-terraform
https://terragrunt.gruntwork.io/
https://terratest.gruntwork.io/
https://www.runatlantis.io/
https://www.openpolicyagent.org/
https://www.conftest.dev/
https://docs.renovatebot.com/
https://github.com/minamijoyo/tfupdate
Code language: JavaScript (javascript)
Final operating principle
Terraform quality is not produced by Terraform alone.
A production Terraform system combines:
Correct code
+ reproducible versions
+ secure identities
+ protected state
+ automated lint/security/test gates
+ visible cost
+ reviewable plan
+ policy where it adds real value
+ controlled execution
+ post-deployment verification
Code language: PHP (php)
That combination turns Terraform from a command-line tool into an engineering platform.
I’m Rajesh Kumar, a DevOps, SRE, DevSecOps, Cloud, and Platform Engineering expert passionate about sharing practical knowledge, real-world experiences, and industry best practices. I have worked at Cotocus and regularly write about technology, travel, investing, health, product reviews, and digital marketing through my various platforms.
I publish technical articles at DevOps School, travel stories at Holiday Landmark, stock market insights at Stocks Mantra, health and fitness guidance at My Medic Plus, product reviews at TrueReviewNow, and SEO and digital marketing strategies at Wizbrand.
Find Trusted Cardiac Hospitals
Compare heart hospitals by city and services โ all in one place.
Explore Hospitals