Part 1 — The 004 Specifics (What's New/Emphasised)

1.1 create_before_destroy — Blue/Green Deployments

resource "aws_instance" "web" {
  lifecycle {
    create_before_destroy = true
  }
}
[!!!]
Order of operations:
  1. Creates the new resource first
  2. Updates dependencies to point to the new resource
  3. Destroys the old resource last
Use case: web servers, load balancers, auto-scaling groups — anything needing zero downtime during updates.
[!!!]

When using create_before_destroy on a launch template with an auto-scaling group, add it to both resources — not just the launch template.

1.2 prevent_destroy — Guardrail Against Accidents

resource "aws_db_instance" "prod" {
  lifecycle {
    prevent_destroy = true
  }
}
[!!!]

prevent_destroy = true stops the entire destroy operation with an error. No partial destroys — the whole apply fails. Use case: databases, persistent volumes, DNS records.

[TRAP]

To actually destroy a resource with prevent_destroy, you must set it to false and re-apply first. You cannot override it at runtime.

[TRAP]

prevent_destroy and ignore_changes are different: ignore_changes = don't revert manual drift on those attributes. prevent_destroy = cannot be deleted at all.

1.3 ignore_changes and replace_triggered_by

RuleWhat It Does
ignore_changes = [tag, label]Ignores drift on the listed attributes. Does NOT prevent the resource from being destroyed via other means.
replace_triggered_by = [resource.x]Forces replacement of this resource whenever the referenced resource or attribute changes.
[!!!]
The four validation types and when each runs:
TypeWhere DefinedWhen EvaluatedCan use self?Blocks apply?
validationInside variable blockPlan — input timeNoYes
preconditionInside lifecycle blockPlan — before resource creationNoYes
postconditionInside lifecycle blockAfter apply — resource existsYes (self.xxx)Yes
checkTop-level HCL blockAfter applyYesNo — warning only
[!!!]

check blocks are non-blocking — they warn and continue. postconditions are gates — they fail the apply. This distinction appears on every practice exam.

[TRAP]
Memory rule:
  • validation = checks variable INPUT (before plan even starts)
  • precondition = checks BEFORE resource is created (during plan)
  • postcondition = checks AFTER resource is created (blocks apply if failed)
  • check block = independent assertion, NEVER blocks apply

2.1 Code Examples

Variable Validation

variable "environment" {
  type = string
  validation {
    condition     = contains(["dev", "staging", "prod"], var.environment)
    error_message = "Environment must be dev, staging, or prod."
  }
}

Precondition

resource "aws_instance" "web" {
  ami           = var.ami_id
  instance_type = var.instance_type

  lifecycle {
    precondition {
      condition     = can(regex("^ami-", var.ami_id))
      error_message = "AMI ID must start with 'ami-'"
    }
  }
}

Postcondition (uses self)

resource "aws_instance" "web" {
  ami           = var.ami_id
  instance_type = var.instance_type

  lifecycle {
    postcondition {
      condition     = self.public_ip != ""
      error_message = "Instance must have a public IP."
    }
  }
}

Check Block (non-blocking)

check "database_encryption" {
  assert {
    condition     = aws_db_instance.prod.storage_encrypted == true
    error_message = "Production database MUST be encrypted."
  }
}
[!!!]
The hierarchy:
HCP Terraform Organisation
│
├── Project: "Platform Team"
│   ├── Workspace: networking-prod
│   ├── Workspace: networking-staging
│   └── Workspace: networking-dev
│
├── Project: "App Team A"
│   ├── Workspace: app-prod
│   └── Workspace: app-dev
│
└── Project: "App Team B"
    ├── Workspace: services-prod
    └── Workspace: services-dev
AspectWorkspacesProjects
PurposeMaps to an individual Terraform config (state, vars, runs)Groups related workspaces — org/team structure
LevelIndividual environment (dev, staging, prod)Team or application level
Permission controlOrg-wide only (older model)Per-project RBAC (finer control)
New in 004?No (existed in 003)Yes — new emphasis
[SCENARIO]

"Your org has 50 teams. How do you organise workspaces for proper access control?" → Create a Project per team, with that team's workspaces inside.

3.1 Ephemeral Values and Write-Only Arguments

[NEW]
Ephemeral values — used only during provisioning, NOT stored in the state file. Improves security by keeping sensitive data out of terraform.tfstate.
[NEW]
Write-only arguments — set but not visible in state. Example: secret_string on aws_secretsmanager_secret_version — Terraform writes the value but does not store it in state. You cannot reference a write-only attribute in an output — Terraform errors immediately.
[!!!]

The exam tests this: sensitive data should be kept out of state. Options: ephemeral values, write-only arguments, or external secrets managers. NOT sensitive = true which only hides from output — the value is still in the state file in plaintext.

Part 2 — Command Gotchas (Trap Answers)

4.1 state mv vs moved block

[!!!]
ApproachMethodTraceable?Preferred?
Old (003 era)terraform state mv old.name new.nameNo — CLI command onlyNo
New (004 emphasis)moved {} block in codeYes — in version controlYes
[TRAP]

Exam question: "Safest way to refactor (rename) a resource?" → Answer: moved {} block in code, not terraform state mv.

moved {
  from = aws_instance.web
  to   = aws_instance.server
}

4.2 -replace vs -target vs -refresh-only

FlagWhat It DoesUse When
terraform apply -replace="res"Forces destroy + recreate of that specific resourceResource is corrupted or needs a forced replacement. Replaces deprecated terraform taint.
terraform apply -target="res"Applies ONLY that resource, skips othersEmergency only — can break dependencies. NOT for routine use.
terraform apply -refresh-onlyUpdates state to match real infrastructure. Does NOT change infrastructure.Accept drift into state without modifying infrastructure.
[!!!]

terraform refresh is deprecated. The modern equivalent is terraform apply -refresh-only.

[TRAP]

The exam asks: "Force recreate a resource" → Answer: -replace. Not -target (selective apply), not taint (deprecated).

4.3 CI/CD Best Practice — Plan File

# BEST PRACTICE for CI/CD
terraform plan -out=plan.tfplan
terraform apply plan.tfplan
# No -auto-approve needed; plan file prevents accidental changes
[!!!]

Using a plan file means terraform apply plan.tfplan applies exactly what was reviewed — no new plan, no prompt. This is the exam-preferred answer for production CI/CD, NOT terraform apply -auto-approve.

[TRAP]

Exam: "Best practice for production CI/CD?" → Plan file (terraform plan -out + terraform apply plan.tffile). NOT terraform apply -auto-approve which skips any review.

4.4 init Flags

FlagWhat It Does
terraform init -upgradeUpgrades provider versions to the latest compatible version. Updates .terraform.lock.hcl.
terraform init -reconfigureRe-initialises without migrating state. Use when changing backend config. Does NOT move existing state.
terraform init -migrate-stateChanges backend AND migrates existing state to the new backend.
[TRAP]

Use -migrate-state when you want to move state to a new backend. Use -reconfigure when you want to reconfigure the backend without migrating existing state (dangerous if you have state!).

4.5 terraform import — Hidden Gotcha

[!!!]
terraform import adds an existing real-world resource to Terraform state. But:
  • You MUST have the resource block defined in code first — import only writes to state, not code.
  • Import does NOT generate code — you must write the resource configuration manually after importing.
  • After import, if the code doesn't match the real resource, terraform plan will show a diff.

4.6 Quick Command Reference

CommandPurposeSafe for Prod?
terraform planPreview changesYes — read-only
terraform applyApply changesOnly with plan file
terraform destroyDelete all managed resourcesNever without prevent_destroy on critical resources
terraform state listList tracked resourcesYes
terraform state showShow resource details from stateYes
terraform state rmRemove resource from state (DANGEROUS)No — use code removal instead
terraform importAdd existing resource to stateRequires matching code first
terraform validateCheck syntax against provider schemasYes
terraform fmtAuto-format .tf filesYes
terraform consoleInteractive expression evaluator / REPLYes — read-only
terraform graphOutput dependency graph in DOT formatYes
terraform apply -refresh-onlySync state with reality without changing infrastructureYes (replaces deprecated terraform refresh)

Part 3 — High-Difficulty Scenario Questions

[Q1] State File Corruption

A developer accidentally runs: terraform state rm aws_db_instance.prod The database is deleted from the state file but still exists in AWS. What are the THREE most dangerous consequences? A) Terraform will automatically recreate the database B) Terraform will ignore the database on next apply C) If someone adds a new resource with the same config, Terraform may try to create a duplicate D) The database is now totally unmanaged E) The state file size increases due to the missing reference F) If the database is deleted manually, Terraform will not know about it

Answers: B, C, D (and F is also correct). After state rm: Terraform ignores the resource on the next plan/apply (B). It has no knowledge it exists. A new resource block with the same config may attempt to create a duplicate (C). The real resource is now entirely unmanaged — no lifecycle protection, no drift detection (D). If the real resource is manually deleted later, Terraform won't report it as missing (F). Option A is wrong — Terraform does NOT automatically recreate it. Option E is wrong — state file would be smaller, not larger.
[Q2] Team Isolation with Projects

Your org uses HCP Terraform. You need: - Platform team: manage networking across all environments - App Team A: only manage their app resources - App Team B: only manage their services All workspaces are currently flat under one organisation. Best way to achieve team isolation without giving everyone admin access? A) Use IAM roles in HCP Terraform for each team member B) Create a Project per team, put their workspaces inside C) Create separate HCP Terraform organisations per team D) Use workspace naming conventions and enforce via policy-as-code E) Use team tokens with different permissions per workspace

Answer: B. Projects are the correct isolation unit in HCP Terraform 004. Each team gets a Project, and their workspaces live inside it. This gives per-project RBAC without splitting into separate organisations (which would break cross-team visibility). Option C (separate orgs) is over-engineered and breaks shared policy management. Options A and E are workarounds, not the canonical solution.
[Q3] Zero-Downtime Deployment

You manage an auto-scaling group with a launch template. Tomorrow you will update the AMI to patch a security vulnerability. You CANNOT have any downtime. What's the minimum configuration you must add? A) lifecycle { create_before_destroy = true } on the launch template only B) lifecycle { create_before_destroy = true } on the ASG only C) lifecycle { prevent_destroy = true } on both D) lifecycle { create_before_destroy = true } on BOTH resources E) Add force_delete = true to the ASG F) Nothing — it's automatic with "$Latest"

Answer: D. Both the launch template AND the auto-scaling group need create_before_destroy = true. Adding it to only one resource (A or B) is insufficient — the ASG still tries to destroy the old launch template before the new ASG instances are healthy. Option C (prevent_destroy) protects against deletion, not against downtime during updates. Option F is wrong — $Latest tracks the latest version but does not control destruction order.
[Q4] Moved Blocks vs State Commands

You want to move resources from the root module into module.storage. Current state: aws_s3_bucket.storage aws_s3_bucket_versioning.storage What's the SAFEST way to perform this refactor without destroying resources? A) terraform state mv aws_s3_bucket.storage module.storage.aws_s3_bucket.storage B) Add moved {} blocks in the new module and apply C) terraform destroy followed by terraform apply D) Use terraform import to re-import after moving the code E) Backup state, run state mv commands, test carefully F) Both A and E (run state mv commands and verify)

Answer: B. moved {} blocks in code is the 004-preferred safe refactoring approach. It is traceable in version control, repeatable, and safe. terraform state mv (A, E, F) is the old approach — it works but is not tracked in code, easy to run twice accidentally, and harder to audit. Option C destroys real infrastructure. Option D (import) is a workaround that leaves the code disconnected from state.
[Q5] Validation Execution Order

You have variable validation (allows only t3/t4 micro/small/medium), a precondition (AMI must be x86_64), and a postcondition (instance must get a public IP). Someone runs: terraform apply -var="instance_type=t3.micro" -var="ami_id=ami-windows-arm64" The ami-windows-arm64 AMI is ARM64 architecture, not x86_64. What will happen? A) Apply succeeds; postcondition fails because no public IP B) Apply fails at precondition; wrong architecture C) Apply fails at variable validation; wrong architecture D) Apply succeeds for variable validation but fails at postcondition E) Terraform crashes due to architecture mismatch F) Apply succeeds for everything

Answer: B. The variable validation checks instance_type — "t3.micro" is valid, so validation passes. The precondition checks the AMI architecture BEFORE the resource is created. Since the AMI is ARM64 (not x86_64), the precondition fails and the apply is blocked before any infrastructure is touched. The postcondition never runs because the resource was never created. Option C is wrong — variable validation only checks the instance_type format, not the AMI architecture.

6.1 The Four Shifts from 003 to 004

Topic003 Era004 Now
Organisation structureFlat workspacesProjects > Workspaces (hierarchy)
Resource refactoringterraform state mv CLImoved {} blocks in code (traceable)
ValidationVariables onlyPreconditions + Postconditions + Check blocks
Security / secretsStore in state (sensitive = true)Ephemeral values + write-only arguments (NOT in state)

6.2 Scenario Pattern Quick Answers

[1] Organise 50 teams

Create a Project per team in HCP Terraform. Put each team's workspaces inside their project.

[2] Safely rename a resource

Add a moved {} block in code. Apply. Do NOT use terraform state mv.

[3] Prevent accidental DB deletion

lifecycle { prevent_destroy = true }. Stops the entire apply if destroy is attempted.

[4] Zero-downtime AMI update

lifecycle { create_before_destroy = true } on BOTH the launch template AND the ASG.

[5] Validate infrastructure after creation

Use postcondition block (blocks apply if failed) or check block (warning only).

[6] Validate input values

Use validation {} in the variable block (runs before plan). Use precondition inside lifecycle to check at plan time against data sources.

[7] Force recreate a resource

terraform apply -replace="resource.address". Replaces deprecated terraform taint.

[8] Safe CI/CD production apply

terraform plan -out=plan.tfplan then terraform apply plan.tfplan. NOT -auto-approve.

[9] check block vs postcondition

check block = warning only, never blocks apply. postcondition = hard gate, fails the apply if condition is false.

[10] sensitive = true scope

Only hides value from plan output and terraform output. State file STILL stores value in plaintext. Use ephemeral values or write-only args to keep secrets out of state entirely.

← Back to Portal