AI writes Terraform fast and wrong in specific, predictable ways: invented resource attributes, deprecated argument names, plausible-but-nonexistent data sources, and defaults that are insecure or expensive. Current research on LLM-generated HCL confirms even frontier models hallucinate resource types and attributes.
Tier: Core · Workflow area: Infrastructure as Code
The professional response is not to avoid AI IaC — it is to make the verification chain non-optional: validate → plan → policy scan → cost estimate → human review, every time, wired so skipping a link is impossible. This playbook is the anchor pattern for the whole track.
Skip AI for terraform state surgery and provider version upgrades on live stateful infra unless you are following the dedicated playbooks (pb-10, pb-12).
plan (not apply) can run.terraform validate, TFLint, Checkov (or tfsec/Trivy), Infracost — all free/OSS.Prompt with constraints, versions, and conventions — not just intent.
Write a Terraform module for an AWS RDS PostgreSQL instance.
Constraints:
- Terraform >= 1.7, AWS provider ~> 5.40. Use only attributes that exist
in this provider version.
- Multi-AZ toggle via variable, default true for prod workspaces.
- Storage encrypted with a KMS key passed in as a variable (no default key).
- No public accessibility, deletion protection on, backups 14 days.
- Follow the variable/output naming style in ./modules/elasticache (attached).
- Outputs: endpoint, port, security group id.
Do not invent attributes. If unsure an attribute exists in provider 5.x,
say so instead of guessing.
Gate 1 — validate + lint. Catches nonexistent attributes and type errors in seconds:
terraform init -backend=false && terraform validate
tflint --init && tflint
Feed errors straight back to the assistant; this loop usually takes 2–3 rounds on unfamiliar providers.
Gate 2 — plan against the sandbox. Validate proves syntax; only plan proves the provider accepts the semantics:
terraform plan -var-file=sandbox.tfvars -out=tfplan
terraform show -json tfplan > tfplan.json
Read the plan yourself. Count resources. Anything being created that you did not ask for (default security groups, log groups, random passwords in state) gets challenged.
Gate 3 — policy scan. Checkov on the plan JSON catches the insecure defaults AI loves:
checkov -f tfplan.json --compact
conftest test tfplan.json --policy policy/ # org policies from pb-07
Gate 4 — cost estimate. AI-drafted modules routinely default to oversized instances and gp3 volumes with provisioned IOPS nobody asked for:
infracost breakdown --path . --format table
Compare against your expectation before review, not after the first invoice.
Gate 5 — human review with the chain outputs attached. The PR includes: plan summary, Checkov results, Infracost diff. The reviewer reviews intent and blast radius — the mechanical checks are already done. Wire gates 1–4 into CI so the chain runs on every IaC PR whether or not AI was involved.
The chain is cheap, ordered by cost-of-failure, and entirely OSS — validate catches syntax lies in seconds, plan catches semantic lies in minutes, policy and cost catch the expensive lies before apply. The skill being assessed is the chain, not the prompt.
apply. Consider an alias making terraform apply unavailable in the agent's environment.pulumi preview, cdk diff replace plan; Checkov supports both; unit tests partially replace validate.The chain IS the verification; the pass bar explicitly:
terraform validate + TFLint clean.source = "terraform-aws-modules/rds/aws" is real; subtle variants are not. Verify registry sources exist at the pinned version.Client account IDs, CIDR plans, and naming conventions are confidential. Draft with placeholders (CLIENT_CIDR, ACCOUNT_ALIAS) on any approved assistant, substitute locally, and run the chain entirely inside the client environment — every chain tool is OSS and offline-capable. If the client provides Bedrock/Azure OpenAI in-tenancy, use it and skip the placeholder dance. Never paste terraform plan output (it contains real IDs) into unapproved tools.