HashiCorp Terraform Associate 004 — Study Guide
Final Exam Attack Plan
Third-attempt pass guarantee strategy built from two official exam failures and full question bank analysis. Targets exactly the sections and traps where the exam catches you out.
| Section | Attempt 1 (Feb 2026) | Attempt 2 (Apr 2026) | Direction |
|---|---|---|---|
| 1. IaC with Terraform | Review Needed | Review Needed | ➡️ Stuck |
| 2. Terraform Fundamentals | Meets Expectations | Meets Expectations | ✅ Solid |
| 3. Core Terraform Workflow | Meets Expectations | Meets Expectations | ✅ Solid |
| 4. Terraform Configuration | Review Needed | Review Needed | ➡️ Stuck |
| 5. Terraform Modules | Meets Expectations | Meets Expectations | ✅ Solid |
| 6. State Management | Review Needed | Meets Expectations | ⬆️ Fixed |
| 7. Maintain Infrastructure | Review Needed | Meets Expectations | ⬆️ Fixed |
| 8. HCP Terraform | Review Needed | Intense Study | ⬇️ REGRESSED |
Key insight: Practice quiz scores (94% on Domain 1) did not translate because the real exam uses different wording, scenario framing, and trap answers. The questions in this portal use real-exam-style framing to close that gap.
1.1 The HCP Terraform Hierarchy — Burn This Into Memory
ORGANISATION │ ├── TEAMS (groups of users with permissions) │ ├── PROJECTS (groups of workspaces with shared permissions) │ │ │ ├── WORKSPACE A (state + vars + runs + VCS link) │ ├── WORKSPACE B │ └── WORKSPACE C │ └── DEFAULT PROJECT (all new workspaces go here by default)
Every workspace belongs to exactly ONE project. All new workspaces go to the Default Project unless specified. The Default Project can be renamed but NOT deleted.
1.2 CLI Workspaces vs HCP Terraform Workspaces — COMPLETELY DIFFERENT
| Feature | CLI terraform workspace | HCP Terraform Workspace |
|---|---|---|
| State | Separate path, same backend | Completely isolated |
| Variables | None (shared config) | Per-workspace Terraform + env vars |
| Permissions | None (all or nothing) | Full RBAC |
| VCS connection | None | Yes — specific branch |
| Run history | None | Full audit trail |
"Workspaces" in HCP Terraform are NOT the same as running terraform workspace new. They are far more powerful — full isolation units.
1.3 The Three Execution Modes
| Mode | Where Plan/Apply Runs | Where State Lives | When to Use |
|---|---|---|---|
| Remote (default) | HCP Terraform workers | HCP Terraform | Standard team workflow |
| Local | Your machine | HCP Terraform | Need local tools, remote state |
| Agent | Self-hosted agent | HCP Terraform | Private network resources |
In local mode, plan/apply run on YOUR machine — but state STILL lives in HCP Terraform. "Local execution" ≠ "local state".
An agent is needed when HCP Terraform cannot reach your infrastructure directly (private VPC, on-premises). Not for general use.
1.4 The Three Workflow Types
| Workflow | How a Run Starts | Who Uses It |
|---|---|---|
| VCS-driven | Push/merge to connected branch | Teams using GitOps |
| CLI-driven | terraform plan from local terminal | Developers preferring CLI |
| API-driven | REST API call | CI/CD systems, automation |
VCS-driven critical rules: Push to connected branch → triggers plan. Open a PR → triggers speculative plan (preview only, CANNOT be applied). Push to any other branch → NOTHING.
A push to a feature branch does NOT trigger a run. Only the connected branch triggers runs.
A speculative plan is triggered by a pull request and CANNOT be applied directly. It is preview-only.
1.5 Sentinel Policy Enforcement Levels
- Advisory — Warning logged, run always continues. Never blocks.
- Soft-mandatory — Run blocked by default. Authorised users CAN override and apply anyway.
- Hard-mandatory — Run blocked unconditionally. Nobody can override — not even org owners.
Sentinel runs after the plan, before the apply — not after apply. OPA is an alternative to Sentinel (same position in lifecycle).
1.6 HCP Terraform Run Lifecycle
- Pending → queued, waiting for worker
- Planning →
terraform planexecutes - Cost Estimating → monthly cost delta calculated
- Policy Check → Sentinel or OPA evaluates
- Confirmation → waiting for human approval (unless auto-apply)
- Applying →
terraform applyexecutes - Applied → complete
Cost estimation comes BEFORE policy check — Sentinel can then enforce cost limits in policies.
1.7 HCP Terraform vs Terraform Enterprise
| Feature | HCP Terraform | Terraform Enterprise |
|---|---|---|
| Hosting | SaaS (HashiCorp-managed) | Self-hosted (your servers) |
| Air-gapped | No — requires internet | Yes |
| Free tier | Yes — up to 500 resources | No |
| SAML SSO | Paid plans only | Yes |
| Audit logging | Paid plans only | Yes |
Air-gapped (no internet) = Terraform Enterprise. SaaS with free tier = HCP Terraform.
1.8 cloud Block vs backend Block
terraform {
cloud { # For HCP Terraform
organization = "my-org"
workspaces { name = "prod" }
}
}
terraform {
backend "s3" { # For all other backends
bucket = "my-state"
key = "prod/terraform.tfstate"
}
}
cloud and backend are mutually exclusive. Using both in the same configuration causes a Terraform error.
1.9 Variable Sets
A variable set is a reusable collection of variables applied to multiple workspaces. Ideal for shared cloud credentials — update once, all workspaces pick it up.
Critical rule: Workspace-level variables ALWAYS override variable set variables.
Sensitive variables in HCP Terraform are write-only — once saved, they can never be read back, only overwritten or deleted. Even HashiCorp cannot read them.
Terraform DOES vs DOES NOT:
| Terraform DOES | Terraform DOES NOT |
|---|---|
| Provision infrastructure (VMs, networks, databases) | Install software on servers |
| Detect and correct infrastructure drift | Prevent drift from occurring |
| Reduce errors through automation | Eliminate ALL errors |
| Enable disaster recovery by rebuilding from code | Guarantee zero downtime |
Declarative vs Imperative:
- Declarative — define desired end state, tool figures out HOW: Terraform, CloudFormation, Bicep, Pulumi
- Imperative — define step-by-step instructions: Bash scripts, AWS CLI sequences
Idempotency: Running the same config multiple times produces the same result. No duplicates. Terraform checks current state and only makes necessary changes.
| Scenario | What Terraform Does |
|---|---|
| Config: 3 instances · Actual: 3 | Nothing |
| Config: 3 instances · Actual: 2 | Creates 1 more |
| Config: 3 instances · Actual: 5 | Destroys 2 |
"IaC eliminates ALL infrastructure errors" — FALSE. It reduces them. Logic errors in code are consistently deployed.
"Terraform prevents drift" — FALSE. Detects and corrects on next apply. Cannot stop manual changes from happening.
"Pulumi is imperative because it uses programming languages" — FALSE. Pulumi is declarative despite using TypeScript/Python syntax.
Shift-left = moving validation, testing, and security checks EARLIER in the dev lifecycle — in code review and CI, not production. NOT about moving from cloud to on-premises.
Snowflake server = manually configured server drifted to a unique, unreproducible state. IaC solution: all servers defined as code, every deployment identical.
3.1 Variable Precedence — Memorise This Order
- Default value in variable block
- TF_VAR_ environment variable
- terraform.tfvars file (auto-loaded)
- *.auto.tfvars files (alphabetical)
- -var-file flag
- -var flag on CLI (always wins)
DE-TAFv (Default → Env → Tfvars → Auto.tfvars → File-flag → Var-flag)
terraform.tfvars is loaded automatically. A file named other.tfvars is NOT — you need -var-file=other.tfvars explicitly.
3.2 count vs for_each — Critical Distinction
| Feature | count | for_each |
|---|---|---|
| Input | A number (integer) | A map or set |
| Index type | Zero-based integer [0], [1] | String key ["dev"], ["prod"] |
| Reorder safe? | NO — removing [0] shifts all | YES — keys are stable |
| Reference | aws_instance.web[0] | aws_instance.web["dev"] |
Removing the FIRST item in a count resource shifts ALL indices — Terraform may destroy and recreate the others. Use for_each for named instances.
for_each requires a map or set. To use a list, convert with toset(): for_each = toset(["dev","staging","prod"]).
3.3 Custom Conditions Summary
| Type | Where | When Evaluated | Can use self? | Blocks apply? |
|---|---|---|---|---|
| validation | variable block | Plan — input time | No | Yes |
| precondition | lifecycle block | Plan — before resource | No | Yes |
| postcondition | lifecycle block | After apply — resource exists | Yes | Yes |
| check block | Top-level HCL | After apply | Yes | No — warning only |
check blocks are non-blocking — they warn and continue. postconditions are gates — they fail the apply. This distinction is frequently tested.
3.4 Sensitive Values
sensitive = true hides values from plan output and terraform output. It does NOT encrypt or protect the value in the state file. The state file always stores values in plaintext.
| Command | What It Does | Requires init? |
|---|---|---|
terraform init | Downloads providers, initialises backend | Is init |
terraform validate | Checks syntax against provider schemas | Yes |
terraform plan | Preview changes — no modifications | Yes |
terraform apply | Execute changes (prompts for confirmation) | Yes |
terraform destroy | Destroy all managed resources | Yes |
terraform fmt | Auto-format .tf files | No |
terraform import | Add existing resource to state | Yes |
terraform console | Interactive expression evaluator | Yes |
terraform show | Display state or saved plan | Yes |
terraform output | Show output variable values from state | Yes |
terraform fmt — formats code. terraform validate — checks syntax. terraform plan — checks API state. These are three different things.
terraform refresh is DEPRECATED. Modern replacement: terraform apply -refresh-only (shows what would change in state before applying).
terraform apply -refresh-only updates the state file to match reality. No infrastructure is modified. Accepts drift into state.
terraform plan -destroy — previews what would be destroyed. terraform apply -replace=ADDR — forces replacement of a specific resource (replaces deprecated terraform taint).
State file maps code addresses (aws_instance.web) to real cloud resource IDs (i-0a1b2c3d). Without state, Terraform cannot track what it manages.
Never commit the state file to version control — it contains sensitive attributes in plaintext. Use a secure remote backend (S3+KMS, HCP Terraform).
moved {
from = aws_instance.old_name
to = aws_instance.new_name
}
Without a moved block: Terraform destroys old resource and creates new one. Always use moved blocks when renaming.
State locking: S3 backend requires a separate DynamoDB table. HCP Terraform handles locking automatically — no DynamoDB needed.
.terraform.lock.hcl locks provider versions — NOT state. State locking is separate (DynamoDB or HCP Terraform).
| Rule | What It Does |
|---|---|
prevent_destroy = true | Errors on any plan that would destroy this resource. Entire destroy fails. |
create_before_destroy = true | Creates replacement first, then destroys old. Zero-downtime updates. |
ignore_changes = [attr1, attr2] | Ignores drift on specified attributes. Does not prevent destruction. |
replace_triggered_by = [...] | Forces replacement when another resource or attribute changes. |
prevent_destroy does not skip the resource — it stops the entire destroy operation. No partial destroys.
ignore_changes and prevent_destroy are different: ignore = don't revert changes; prevent_destroy = cannot be deleted.
terraform taint is deprecated. Use terraform apply -replace=RESOURCE_ADDRESS to force replacement.
| Day | Focus | Actions |
|---|---|---|
| Day 7 | Baseline & Gap Audit | 20-question timed mini-mock. Categorise every miss by section. Identify your top-3 weaknesses from this session. |
| Day 6 | HCP Terraform Reset | Read Section 1 of this plan cold. Do the 30 trap-heavy HCP Terraform questions from the practice exam. Write the hierarchy from memory. |
| Day 5 | IaC Concepts + Configuration | Sections 2 and 3 of this plan. Flashcard: variable precedence order. Flashcard: count vs for_each distinction. Do 20 IaC + config questions. |
| Day 4 | State + Lifecycle | Sections 5 and 6. moved blocks, prevent_destroy, create_before_destroy. DynamoDB vs HCP Terraform locking. 20 state questions. |
| Day 3 | Mixed Full Mock | Take the full 57-question mock from this portal (timed). Review every miss — identify pattern: is it HCP or IaC or config? |
| Day 2 | Exam Prep (Set 2) + Weak Areas | Take the Exam Prep (Set 2) — harder, trap-heavy. Spend remaining time on the section that showed the most misses today. |
| Day 1 | Light Consolidation Only | Read all [!!!] items from this plan. Read all [TRAP] items. Run a 10-question confidence check. Sleep. No new content today. |
Use these in your final pass before exam day.
init → validate → plan → apply → destroy. Can't plan without init. Can't validate without init.
.terraform.lock.hcl = provider version lock. NOT state locking. State locking = DynamoDB (S3) or HCP Terraform (automatic).
HCP Workspace = full isolation unit (state, vars, RBAC, runs). CLI workspace = just a separate state path, no RBAC.
Plan → Cost Estimate → Policy Check → Confirm → Apply. Sentinel runs BEFORE apply.
No internet / private network only = Terraform Enterprise (self-hosted). HCP Terraform always needs internet.
CLI -var flag always wins. Default value always loses. Order: default → TF_VAR_ → .tfvars → auto.tfvars → -var-file → -var.
Updates STATE to match infrastructure. Does NOT change infrastructure. Accepts drift into state.
Hides from OUTPUT only. State still stores in plaintext. Encrypt the backend separately.
Removing item at index 0 shifts ALL higher indices → potential destroy/recreate of all resources. Use for_each instead.
Score each item 0–2 · 0 = shaky · 1 = partial · 2 = confident from memory
| # | Skill | Your Score (0–2) |
|---|---|---|
| 1 | HCP Terraform hierarchy (org → project → workspace → team) | |
| 2 | Three execution modes (Remote / Local / Agent) | |
| 3 | Three workflow types (VCS / CLI / API) | |
| 4 | Sentinel enforcement levels (Advisory / Soft-mandatory / Hard-mandatory) | |
| 5 | HCP Terraform run lifecycle order | |
| 6 | Variable precedence order (all 6 levels) | |
| 7 | count vs for_each distinction and index shifting risk | |
| 8 | precondition vs postcondition vs check block differences | |
| 9 | moved block purpose and when to use it | |
| 10 | prevent_destroy behaviour (entire destroy fails, not just that resource) | |
| 11 | Air-gapped → Terraform Enterprise. SaaS → HCP Terraform. | |
| 12 | sensitive = true scope (output only, NOT state encryption) |
- 22–24 → Exam ready ✓
- 18–21 → One focused HCP Terraform revision block needed
- 14–17 → Two targeted blocks: HCP Terraform + IaC/Config
- 0–13 → Rebuild the stuck sections (1, 2, 3) before sitting the exam