Education › Certs › Stage 2: Kubernetes & infrastructure

HashiCorp Terraform Associate

Workflow, state, modules, providers, workspaces and HCP Terraform, with the questions the exam loves to ask.

Associate ~40 min read Module 4 of 6

The HashiCorp Terraform Associate is a one-hour multiple-choice exam that tests whether you understand how Terraform actually works — providers, state, the plan-apply workflow, modules, expressions, drift, import and HCP Terraform — rather than whether you can memorise a cloud's resource types. Its questions are short and specific, which makes it the most predictable exam in this track: know the eight objectives of the current version (004), have run every command in them, and understand the handful of concepts people get wrong (what state is for, what terraform init does and does not do, how variable precedence works, what locking protects). This guide follows the 004 objectives exactly, gives the commands and rules behind each, and lays out a three-week plan. Confirm the exam details on HashiCorp's certification page before booking.

After this module you can
  • Describe the Terraform Associate 004 format and its eight objectives
  • Explain providers, state, the core workflow and the configuration language at the depth the questions require
  • Use modules, remote state with locking, import and drift handling correctly
  • Describe HCP Terraform workspaces, projects, runs, variables and policy at the level tested
  • Follow a three-week plan that runs every command in the objectives

The exam at a glance

Terraform Associate (004) is a one-hour, multiple-choice and multiple-select exam taken online with a proctor, costing 70.50 USD plus tax, valid for two years. HashiCorp says version 004 is a significant update from 003, adding custom conditions validation and HCP Terraform workspace organisation among its new topics. The objectives are published in full with a review guide and tutorials on HashiCorp's developer site, which is the study material to trust. Questions are conceptual and command-level ("which command…", "what happens when…", "which block…"), and several test exact behaviour that differs from intuition.

ObjectiveTests
1. Infrastructure as Code with TerraformWhat IaC is, its advantages, multi-cloud and service-agnostic workflows
2. Terraform fundamentalsInstalling and versioning providers, how providers are used, multiple providers, how state is used
3. Core Terraform workflowwrite, plan, apply; init, validate, plan, apply, destroy, fmt
4. Terraform configurationresource vs data, references, variables and outputs, complex types, expressions and functions, dependencies, custom conditions, sensitive data and Vault
5. Terraform modulesSources, variable scope, using modules, versioning
6. Terraform state managementLocal backend, locking, remote backend block, drift and state operations
7. Maintain infrastructureImport, inspecting state with the CLI, verbose logging
8. HCP TerraformCreating infrastructure, collaboration and governance, workspaces and projects, integration
Note

The DevOps track's Terraform module covers the practice; this guide is about the exam's specific angles and the facts it checks. Run every command below on a real project (the zero-to-production infrastructure works) — the questions assume you have.

Fundamentals: providers and state (objectives 1–2)

Terraform is provider-based: the core reads configuration, builds a graph and drives providers (plugins) that talk to APIs — AWS, Azure, Kubernetes, GitHub, a database — which is why one workflow spans many services and clouds. Providers are declared in required_providers with a source and a version constraint; terraform init downloads them into .terraform/ and records exact versions in .terraform.lock.hcl, which you commit so every run uses the same builds. Multiple instances of one provider (two regions) use alias. The exam checks constraint syntax (~> 5.0 allows 5.x but not 6.0) and that terraform init -upgrade is what moves within constraints.

State is Terraform's record of what it manages: a mapping from configuration addresses to real resource ids and attributes, used to plan changes, detect drift and know what to destroy. It is stored in terraform.tfstate locally by default, in a backend for teams, and it can contain sensitive values in plain text, so it must be protected and never committed. The exam asks why state exists (mapping, metadata, performance via caching), what happens without it (Terraform would create duplicates), and that refresh reads real infrastructure to update state before planning.

The blocks the exam expects you to read: provider requirements with constraints, a provider alias, and a remote backend with locking.
hcl
terraform {
  required_version = ">= 1.10"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.80"      # >= 5.80, < 6.0
    }
  }
  backend "s3" {
    bucket       = "acme-tfstate"
    key          = "prod/network.tfstate"
    region       = "eu-west-1"
    encrypt      = true
    use_lockfile = true         # S3-native locking (Terraform 1.10+)
  }
}

provider "aws" {
  region = "eu-west-1"
}

provider "aws" {
  alias  = "us"
  region = "us-east-1"
}

resource "aws_acm_certificate" "cdn" {
  provider    = aws.us          # CloudFront certificates must live in us-east-1
  domain_name = "shop.example.com"
  validation_method = "DNS"
}

Workflow and configuration (objectives 3–4)

The core workflow is write, plan, apply. terraform init prepares the directory (backend, providers, modules) and must be rerun when any of those change; it never modifies infrastructure. terraform validate checks syntax and internal consistency without touching APIs (it needs init first). terraform plan refreshes state and shows the proposed changes; -out=FILE saves a plan that apply FILE executes exactly, with no further prompt. terraform apply without a saved plan re-plans and asks for confirmation unless -auto-approve. terraform destroy (or apply -destroy) removes everything in state. terraform fmt rewrites files to canonical style; fmt -check is for CI.

Configuration: resource blocks create and manage; data blocks read existing things. References (aws_vpc.main.id) create implicit dependencies; depends_on adds explicit ones when there is no reference. Variables have types (string, number, bool, list, map, set, object, tuple), defaults, validation blocks, sensitive = true (redacted in output, still in state), and a precedence order the exam loves: environment variables TF_VAR_name, then terraform.tfvars, then *.auto.tfvars in filename order, then -var and -var-file on the command line, later ones winning. Outputs expose values, can be marked sensitive, and are read from state. Expressions include conditionals, for expressions, splat, dynamic blocks, and built-in functions (lookup, merge, flatten, jsonencode, file, templatefile); there are no user-defined functions.

Custom conditions (new in 004): a variable validation, a precondition on a resource, and a postcondition that checks the real result.
hcl
variable "instance_type" {
  type = string
  validation {
    condition     = can(regex("^t3\\.", var.instance_type))
    error_message = "Only t3 instance types are allowed in this environment."
  }
}

resource "aws_instance" "app" {
  ami           = data.aws_ami.al2023.id
  instance_type = var.instance_type

  lifecycle {
    precondition {
      condition     = data.aws_ami.al2023.architecture == "x86_64"
      error_message = "The selected AMI must be x86_64."
    }
    postcondition {
      condition     = self.public_ip == null
      error_message = "Instances in this module must not receive a public IP."
    }
  }
}
Tip

Sensitive data on the exam: mark variables and outputs sensitive, remember state still holds the values, keep secrets out of code with a secrets manager or the Vault provider, and never rely on .gitignore alone.

Modules and state management (objectives 5–6)

A module is any directory of Terraform files; the root module is where you run commands, and child modules are called with a module block. Sources: local paths, the public or a private registry (namespace/name/provider with a version constraint, which only registry sources support), Git URLs (pin with ?ref=), and archives. Variables are scoped to the module: a child sees only what is passed as inputs, and the parent reads only the child's declared outputs. Providers are inherited by default from the parent unless passed explicitly. terraform get or init downloads modules; -upgrade picks newer versions within constraints.

State management: the local backend is a file; remote backends (S3, Azure Storage, GCS, HCP Terraform and others) share state and support locking, which prevents two applies from corrupting it — with S3 that is the use_lockfile option or a DynamoDB table, and -lock=false exists but is dangerous. terraform state list|show|mv|rm|pull|push inspect and surgically edit state (mv renames without recreating; rm forgets without destroying). Drift is when reality differs from state: plan shows it after refresh; terraform apply -refresh-only updates state to match reality without changing infrastructure; -replace=ADDRESS forces recreation (the old taint). Workspaces (terraform workspace new|select) keep separate state files for the same configuration.

State and drift commands the exam asks about by name.
bash
terraform state list                                   # addresses in state
terraform state show aws_instance.app                  # attributes of one resource
terraform state mv aws_instance.app aws_instance.web   # rename without destroy/create
terraform state rm aws_s3_bucket.legacy                # stop managing; resource stays
terraform apply -refresh-only                          # accept drift into state, no infra changes
terraform apply -replace=aws_instance.app              # force recreate (replaces 'taint')
terraform workspace new staging && terraform workspace select staging
terraform force-unlock LOCK_ID                         # only when a lock is truly stale

Maintaining infrastructure and HCP Terraform (objectives 7–8)

Import brings existing infrastructure under management: write the resource block, then terraform import ADDRESS ID, or declare an import block and let plan generate configuration with -generate-config-out. Import writes to state only; the configuration must match or the next plan shows changes. Inspecting: terraform show prints state or a saved plan; terraform output reads outputs; terraform graph draws dependencies. Logging: TF_LOG (TRACE, DEBUG, INFO, WARN, ERROR) with TF_LOG_PATH writes verbose logs; TF_LOG_CORE and TF_LOG_PROVIDER separate the two.

HCP Terraform (formerly Terraform Cloud; Terraform Enterprise is the self-hosted version) runs Terraform remotely with shared state, locking, run history, variable storage (including sensitive variables encrypted at rest), VCS-driven workflows (a pull request triggers a speculative plan, a merge triggers an apply), team access controls, and policy as code with Sentinel or OPA to enforce rules before apply. Workspaces in HCP Terraform are the unit of state and configuration (unlike CLI workspaces, which are just state files), and projects group workspaces for permissions and organisation. The CLI connects with a cloud block, and runs can be remote, local, or agent-based for private networks. The private registry hosts modules and providers for the organisation, and run tasks integrate external checks.

Connecting a configuration to HCP Terraform: the cloud block selects the organisation and workspace; runs and state move to the platform.
hcl
terraform {
  cloud {
    organization = "acme"
    workspaces {
      name = "network-prod"       # or tags = ["network"] to select several
    }
  }
}

# import block (Terraform 1.5+): declare, then 'terraform plan -generate-config-out=generated.tf'
import {
  to = aws_s3_bucket.assets
  id = "acme-assets-prod"
}
Watch out

Two facts that trip people: terraform init does not create infrastructure or lock state, and terraform state rm does not destroy anything. Read each option for exactly what the command does.

The three-week plan

WeekObjectivesDo
11–4: fundamentals, workflow, configurationBuild a small project from scratch: providers with constraints and an alias, variables of every type with validation, outputs, data sources, a dynamic block, preconditions; run init, validate, plan -out, apply, fmt -check, destroy
25–7: modules, state, maintenanceExtract a module, call it twice with different inputs, pin a registry module; move to an S3 backend with locking; practise state mv/rm, refresh-only, -replace, workspaces; import a bucket both ways; run with TF_LOG=DEBUG
38 plus reviewConnect the project to a free HCP Terraform organisation with a VCS workflow, a workspace variable set, a project, and one Sentinel or OPA policy; then HashiCorp's sample questions and a timed run through the review guide

HashiCorp's own study guide, review guide and tutorials for 004 are the authoritative source and are free; read the review guide's objectives one by one and be able to say a sentence about each. The exam is short: one hour goes quickly, so answer confidently, flag the few you doubt, and return. Most people who have run every command in this guide finish with time to spare.

Hands-on practice

Three-week study plan, condensed

  1. Book the exam for three weeks out. Create a small project (the zero-to-production infrastructure or a fresh VPC-plus-instance) and a free HCP Terraform account.
  2. Week 1: rebuild the project to exercise objectives 1–4: constraints and a provider alias, every variable type, validation and lifecycle conditions, a dynamic block, sensitive outputs. Run the full command set and read every plan line.
  3. Week 2: refactor into a module and call it twice; add a registry module with a version pin; switch to a remote backend with locking and observe a lock during apply; run state mv and rm and import (CLI and import block); force a drift by changing a tag in the console and resolve it with refresh-only; run once with TF_LOG=DEBUG.
  4. Week 3: connect to HCP Terraform with a cloud block, trigger a speculative plan from a pull request, set workspace variables including a sensitive one, create a project, and attach one policy that fails a plan. Then do HashiCorp's sample questions and reread the review guide.
  5. Keep a one-page list of 'exact behaviour' facts: what init does, variable precedence, what rm and mv do, lock semantics, sensitive versus state, registry-only versioning.
  6. Exam day: read every option for exact command behaviour; eliminate options that describe what a command does not do; flag and return.
Cheat sheet

HashiCorp Terraform Associate — at a glance

Main things to focus on

  • Providers are plugins declared with source and version constraints; init downloads them and writes the lock file
  • State maps configuration to real resources; it is sensitive, must be protected, and enables plan, drift detection and destroy
  • init prepares; validate checks syntax offline; plan refreshes and proposes; apply executes; destroy removes; fmt formats
  • Variable precedence: TF_VAR env < terraform.tfvars < *.auto.tfvars < -var/-var-file (later wins); sensitive hides output, not state
  • Modules scope variables; registry sources support version; providers inherit unless passed
  • state mv renames, state rm forgets without destroying, refresh-only accepts drift, -replace recreates, locking prevents concurrent applies

Exam facts (verified Sept 2026, confirm before booking)

Terraform Associate 004 · 1 hour · multiple choice/selectOnline proctored
70.50 USD + tax · valid 2 yearsRegistration
8 objectives: IaC, fundamentals, workflow, configuration, modules, state, maintain, HCP TerraformStudy the review guide by objective
new in 004: custom conditions, HCP workspaces and projectsDo not use only 003 materials

Commands

terraform init [-upgrade] [-reconfigure|-migrate-state]Backend, providers, modules; no infra changes
terraform validateSyntax and consistency; no API calls
terraform plan -out=tfplan; terraform apply tfplanSaved plan applies exactly, no prompt
terraform apply -auto-approve / -refresh-only / -replace=ADDR / -destroyApply variants
terraform fmt -check -recursiveCI formatting gate
terraform show [tfplan] / output [-json] / graphInspect
terraform state list|show|mv|rm|pull|pushState surgery
terraform import ADDR ID / import {} block + -generate-config-outAdopt existing resources
terraform workspace new|select|listCLI workspaces = separate state files
TF_LOG=DEBUG TF_LOG_PATH=tf.logVerbose logging

Configuration rules

version = "~> 5.80">= 5.80, < 6.0
provider "aws" { alias = "us" } / provider = aws.usMultiple provider instances
resource (manage) vs data (read)Objective 4a
implicit dependency via reference; depends_on when noneOrdering
variable { type, default, validation {}, sensitive }Inputs
lifecycle { precondition / postcondition / create_before_destroy / prevent_destroy / ignore_changes }Resource behaviour and checks
dynamic "block" { for_each = ... content {} }Repeated nested blocks
count vs for_each (map/set) Multiple instances; for_each keys are stable
no user-defined functionsBuilt-ins only

Modules, state, HCP

module "x" { source = "ns/name/aws" version = "~> 3.0" }Registry source with version
source = "git::https://...?ref=v1.2.0" / "./modules/x"Git and local sources (no version argument)
backend "s3" { use_lockfile = true }Remote state with locking
-lock=false / force-unlock IDDangerous; only for stale locks
cloud { organization, workspaces { name | tags } }HCP Terraform connection
HCP workspace = state + config + variables + runs; project = group of workspacesNot the same as CLI workspaces
VCS workflow: PR -> speculative plan, merge -> applyCollaboration
Sentinel / OPA policies; run tasks; private registry; agentsGovernance and integration

Common pitfalls

  • Believing init applies changes or that validate contacts the cloud.
  • Getting variable precedence backwards; command-line values win.
  • Thinking sensitive = true removes the value from state.
  • Adding a version argument to a Git or local module source.
  • Using state rm expecting the resource to be destroyed, or destroy expecting only state to change.
  • Confusing CLI workspaces (state files) with HCP Terraform workspaces (full environments).
Quiz

Check your understanding

5 questions · 4 to pass · answers are explained as you go. Your best score is saved on this device only.

Progress and quiz scores are saved in this browser only. Back up or restore on the hub.

Was this lesson useful? Tell me what to improve →