Reviewing Generated Terraform: The Destroy Count, count vs for_each, and a Comment in the Wrong Place

Generated Terraform code can be risky if not carefully reviewed. This article outlines essential checks—especially the destroy count in plans, the difference between count and for_each, and the importance of validation blocks—and offers practical tips for using policy scanners and handling suppress…

When Terraform code is auto‑generated, the temptation to trust the output can lead to costly mistakes. A single misstep—such as an open bucket or a hard‑coded credential—can expose data or delete critical resources. The key to safe automation is a disciplined review process that separates what can be automatically verified from what requires human judgment.

Understanding Terraform Validation

Running terraform validate only checks that your configuration matches the provider schema. It confirms that required arguments are present, types line up, and references resolve. It says nothing about whether the resources you’re describing are a good idea. A bucket that is world‑accessible, a security group that allows 0.0.0.0/0, or an IAM policy with Action: "*" all pass validation because they are syntactically correct, yet they can be disastrous in production.

To catch these semantic issues you need a policy scanner. Tools such as tflint, checkov, or tfsec analyze the intent behind the code and flag potential security or compliance violations. Integrating one of these scanners into your CI pipeline turns a silent validation into an active safety net.

Reading the Terraform Plan

The most valuable piece of information in a plan is the destroy count, not the create or change counts. A typical plan might read: 3 to add, 1 to change, 2 to destroy. The phrase to search for is forces replacement. A replacement is a delete followed by a create. For stateless resources this is often a rolling update, but for stateful resources—such as an RDS instance or an EBS volume—it means data loss.

When you see a line that forces replacement on a stateful resource, stop and review. This single check can prevent accidental data deletion and is worth the few seconds it takes to spot.

Choosing Between count and for_each

Both count and for_each allow you to create multiple instances of a resource, but they behave differently when the underlying list changes. With count, resources are indexed. Removing an item from the list causes Terraform to re‑index, so the resource that was originally third becomes second. The plan shows a modification of the second slot and a destroy of the third slot—nothing is actually deleted.

With for_each, resources are keyed by a unique identifier. Removing an item from the map causes Terraform to delete exactly that item. Therefore, for_each is the safer choice for collections where items may be added or removed over time. Reserve count for simple on/off conditionals or when you truly need an indexed sequence.

Adding Validation Blocks

Copilot can generate boilerplate code, but it often omits validation blocks that constrain variable values. A missing validation can turn a typo into an unintended configuration. For example, a variable named instance_count might be set to 25 by accident, which would pass terraform validate but exceed your intended limits.

Always include a validation block for bounded variables:

  • condition = var.instance_count > 0 && var.instance_count <= 20
  • error_message = "instance_count must be between 1 and 20."

Adding these blocks not only catches errors early but also documents the intended range for future maintainers.

Handling Scanner Suppressions Correctly

When you need to suppress a scanner finding, place the comment inside the resource block, not above it. Scanner tools like Checkov apply the suppression to the line range that includes the block. A comment outside the block is ignored, causing the scan to fail even though the suppression appears correct.

Always provide a brief justification when you suppress a finding. A bare suppression indicates a decision that was not fully considered and can hide real issues.

Protecting Secrets and State

Secrets should never be hard‑coded in a .tf file or committed to a .tfvars file. Use a secret manager and reference the secret via data sources. Remember that any secret referenced in the configuration is stored in the Terraform state file in plaintext. Therefore, the state must be stored in a remote backend with encryption and locking, and the .tfstate file should be added to .gitignore.

Checklist for Safe Terraform Code

  • All variables have a type, description, and validation block.
  • Use for_each for collections; reserve count for simple toggles.
  • No hard‑coded region, account ID, or ARN—use variables or data sources.
  • Secrets come from a secret manager; never commit them to source control.
  • Security group rules that allow 0.0.0.0/0 must have a justification comment.
  • Run a policy scanner in CI and review the destroy count in every plan.

By following these practices, you can harness the power of generated Terraform code without compromising security or reliability.

Why it matters

Automated Terraform code can introduce critical errors that are hard to detect until they cause data loss or security breaches. A disciplined review process protects infrastructure integrity and saves time and money.

Key points

  • Validate syntax with <code>terraform validate</code> but use policy scanners for semantic checks.
  • Check the destroy count and look for <code>forces replacement</code> in plans.
  • Prefer <code>for_each</code> over <code>count</code> for collections to avoid accidental re‑indexing.
  • Add validation blocks to all bounded variables.
  • Place suppression comments inside resource blocks and justify them.
  • Store secrets in a secret manager and keep state encrypted and out of source control.

Frequently asked questions

What does <code>terraform validate</code> actually check?

It verifies that the configuration matches provider schemas, required arguments exist, and references resolve, but it does not assess whether the resources are a good idea.

When should I use <code>count</code> vs <code>for_each</code>?

Use <code>for_each</code> for collections that may change over time; reserve <code>count</code> for simple on/off conditionals or indexed sequences.

How do I properly suppress a Checkov finding?

Place the suppression comment inside the resource block and provide a brief justification; never suppress without context.

Reporting drawn from

More from World

Felo News, House 42, Bridge Colony, Kot Lakhpat, Lahore, Pakistan
+92 308 4354717 · felopronews@gmail.com