Home Posts IaC Security Cheat Sheet [2026]: Terraform & OpenTofu
Developer Reference

IaC Security Cheat Sheet [2026]: Terraform & OpenTofu

IaC Security Cheat Sheet [2026]: Terraform & OpenTofu
Dillip Chowdary
Dillip Chowdary
Tech Entrepreneur & Innovator · May 20, 2026 · 12 min read

Bottom Line

Shift-left IaC security is mostly workflow discipline, not one magic scanner: pin providers, validate early, review plans as sensitive artifacts, and keep state under strong access control. OpenTofu adds native state and plan encryption, while Terraform leans more on backend and platform controls.

Key Takeaways

  • Commit .terraform.lock.hcl; both tools use it to pin provider versions and checksums.
  • validate needs an initialized directory, so use init -backend=false for fast local checks.
  • Saved plans and machine-readable JSON can expose secrets; treat them like credentials, not logs.
  • Use plan -detailed-exitcode for CI gates, and keep -target for incident-only workflows.
  • OpenTofu has native state and plan encryption; Terraform relies on backend or HCP encryption controls.

Shift-left security for infrastructure as code is less about buying another scanner and more about tightening the default path every engineer already uses. For Terraform and OpenTofu, that means validating before remote access, pinning providers with a lock file, reviewing plans as sensitive artifacts, and making state storage boringly secure. The commands and patterns below were verified against official HashiCorp and OpenTofu docs on May 20, 2026, and optimized for breadth over depth.

Key Takeaways

  • Commit .terraform.lock.hcl; both tools use it to pin provider versions and checksums.
  • validate requires an initialized working directory, so init -backend=false is the fast local gate.
  • Saved plans, state, and machine-readable JSON should be handled like secrets, not disposable build output.
  • plan -detailed-exitcode is the clean CI signal for no-change vs change vs failure.
  • OpenTofu adds native state and plan encryption; Terraform pushes that concern into backend and platform choices.
DimensionTerraformOpenTofuEdge
Core shift-left loopinitvalidateplaninitvalidateplanTie
Dependency lock file.terraform.lock.hcl for provider versions and checksums.terraform.lock.hcl for provider versions and checksumsTie
Native state and plan encryptionBackend- or platform-dependentBuilt-in support for encryption at restOpenTofu
Provider mirrorsFilesystem and network mirrorsFilesystem, network, and OCI mirrorsOpenTofu
Plan review in CI-detailed-exitcode and show -json-detailed-exitcode and show -jsonTie
Targeted operationsSupported, but documented as exceptionalSupported, but documented as exceptionalTie

Terraform vs OpenTofu

Bottom Line

If your goal is fewer dangerous IaC changes, both tools reward the same habits: validate before cloud access, pin providers, review plan output carefully, and lock down state. OpenTofu currently gives security-minded teams a notable extra with native state and plan encryption.

What actually changes for security

  • Validation behavior: both tools validate configuration before plan and apply, and both support standalone validate for early feedback.
  • Supply-chain controls: both tools use .terraform.lock.hcl to record provider selections and checksums.
  • State exposure risk: both tools can surface sensitive values through artifacts and automation if you treat state or JSON output casually.
  • Encryption posture: OpenTofu ships native state and plan encryption; Terraform expects you to get encryption from the backend or HCP platform layer.
Watch out: Saved plan files and machine-readable output are not harmless review artifacts. Terraform documents saved plans as potentially cleartext-sensitive, and OpenTofu documents that show -json can return sensitive values in plain text. If you need to share snippets internally, sanitize them first with the Data Masking Tool.

Daily Security Loop

Live Command Filter

Keyboard: / focus search, Esc clear, t jump to top, 1-5 jump sections.

Keyboard Shortcuts

ShortcutActionWhy it helps
/Focus searchJump straight to the command filter.
EscClear searchReset the cheat sheet without touching the mouse.
tScroll to topReturn to the overview fast during review.
1 to 5Jump sectionsMove between compare, loop, config, automation, and choose sections.

Commands Grouped by Purpose

1. Fast local hygiene

  • Use fmt for canonical formatting and cleaner diffs.
  • Use init -backend=false to validate without touching remote state.
terraform fmt -check
terraform init -backend=false
terraform validate -json

tofu fmt -check
tofu init -backend=false
tofu validate -json

2. CI plan gate

  • -detailed-exitcode gives a clean machine signal for no diff, diff, or failure.
  • Save the plan when you need reproducible approval and apply steps.
terraform plan -out=tfplan -detailed-exitcode
terraform show -json tfplan > plan.json

tofu plan -out=tfplan -detailed-exitcode
tofu show -json -plan=tfplan > plan.json

3. Provider supply-chain hardening

  • Mirror providers for controlled installs and reduced internet dependency.
  • Review lock-file changes like dependency upgrades in application code.
terraform providers mirror -platform=linux_amd64 ./mirror

tofu providers mirror -platform=linux_amd64 ./mirror

4. Drift and incident response

  • Use -refresh-only to reconcile state after intentional out-of-band changes.
  • Use force-unlock only when you know the lock is stale and belongs to you.
terraform plan -refresh-only
terraform force-unlock LOCK_ID

tofu plan -refresh-only
tofu force-unlock LOCK_ID

5. Module test runs

  • Use built-in test runners for reusable modules and guardrail assertions.
  • Filter test files to keep feedback loops small during PR review.
terraform test -filter=tests/validations.tftest.hcl

tofu test -filter=tests/validations.tftest.hcl

Secure Config Patterns

Pin providers and make upgrades reviewable

  • Declare provider sources and version constraints in code.
  • Commit .terraform.lock.hcl so checksum and version changes show up in PRs.
  • Do not treat provider upgrades as an incidental side effect of init.
terraform {
  required_version = ">= 1.6.0"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

Keep secrets out of the happy path

  • Mark values as sensitive for safer UI behavior, but do not mistake redaction for storage security.
  • Prefer remote state with encryption and strong access control over local plaintext state on laptops.
  • Pass dynamic backend settings through -backend-config rather than hard-coding environment-specific values everywhere.
variable "db_password" {
  type      = string
  sensitive = true
}

terraform init -backend-config=prod.hcl

Use CLI configuration to constrain provider installs

  • Filesystem mirrors reduce surprise downloads and help air-gapped or tightly controlled runners.
  • Shared plugin caches can reduce repeated downloads, but they are not the same thing as a policy boundary.
plugin_cache_dir = "$HOME/.terraform.d/plugin-cache"

provider_installation {
  filesystem_mirror {
    path    = "/usr/share/terraform/providers"
    include = ["hashicorp/*"]
  }

  direct {
    exclude = ["hashicorp/*"]
  }
}

OpenTofu-only encryption option

  • If native encryption at rest for state and saved plans is a platform requirement, OpenTofu gives you a built-in path instead of pushing that entirely into backend selection.
  • That reduces one class of accidental exposure, but it does not replace access control, key rotation, or artifact hygiene.

Advanced Automation

Encode assumptions with preconditions, postconditions, and checks

  • Use precondition for assumptions you need before a resource is created.
  • Use postcondition for guarantees the resulting object must satisfy.
  • Use check blocks for non-blocking validation that still surfaces dangerous drift or bad outcomes.
resource "aws_instance" "app" {
  ami           = data.aws_ami.app.id
  instance_type = var.instance_type

  lifecycle {
    precondition {
      condition     = data.aws_ami.app.architecture == "x86_64"
      error_message = "The selected AMI must use x86_64."
    }
  }
}

check "private_subnet_only" {
  assert {
    condition     = startswith(aws_instance.app.private_dns, "ip-")
    error_message = "Instance must remain on the private network path."
  }
}

Make plan review machine-friendly, but not casual

  • Use JSON output for automation, but remember that machine-readable artifacts often reveal more than terminal output.
  • Keep retention short for plan files and JSON reports if they can contain secrets or network topology details.
  • Restrict who can download build artifacts from CI.
Pro tip: A practical shift-left pipeline is usually four stages: fmt, init -backend=false, validate -json, then a privileged plan -out job with artifact access locked down to reviewers.

Test modules without pretending they are static files

  • terraform test and tofu test are useful for module contracts and assertions.
  • Tests can create real infrastructure, so run them in dedicated accounts or isolated projects with cleanup discipline.
terraform test -test-directory=tests -filter=tests/outputs.tftest.hcl

tofu test -test-directory=tests -filter=tests/outputs.tftest.hcl

When to Choose Which

Choose Terraform when:

  • Your delivery model already depends on HCP Terraform or Terraform Enterprise workflows.
  • Your team wants the smallest process change from an existing HashiCorp-centered platform.
  • Your encryption, access control, and audit posture are already solved at the backend and platform layers.

Choose OpenTofu when:

  • You want native state and plan encryption in the toolchain itself.
  • You want OCI-based provider mirror options and a more open governance story.
  • You need near-drop-in workflow familiarity but want extra control over artifact handling.

Shared non-negotiables

  • Keep state out of Git.
  • Review lock-file changes in code review.
  • Restrict artifact downloads for plans and JSON exports.
  • Treat -target as a recovery lever, not a normal deployment feature.

Frequently Asked Questions

Is sensitive = true enough to protect Terraform or OpenTofu secrets? +
No. Sensitive mainly changes how values are displayed, but state and plan artifacts can still hold the underlying data. Terraform documents that local state is plaintext by default, and OpenTofu documents that some machine-readable output can return sensitive values in plain text.
Should I commit .terraform.lock.hcl to Git? +
Yes for normal team workflows. Both Terraform and OpenTofu use the lock file to preserve provider version and checksum selections, which makes dependency changes reviewable and reproducible across laptops and CI runners.
What is the safest basic CI gate for IaC pull requests? +
A practical baseline is fmt, then init -backend=false, then validate -json, followed by a privileged plan -detailed-exitcode job. Keep plan files and JSON output behind restricted artifact access because they can expose sensitive data.
Is -target safe for normal Terraform or OpenTofu deployments? +
Treat it as an exception path, not standard delivery. Both projects document targeted operations as special-purpose recovery or workaround tools, because they can bypass the full dependency graph and hide broader change impact.
Do terraform test and tofu test create real infrastructure? +
They can. Terraform explicitly warns that tests may create infrastructure that costs money, and OpenTofu test runs can also apply resources during assertions. Use isolated accounts or projects and watch cleanup carefully.

Get Engineering Deep-Dives in Your Inbox

Weekly breakdowns of architecture, security, and developer tooling — no fluff.

Found this useful? Share it.