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.
- 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.
| Objective | Tests |
|---|---|
| 1. Infrastructure as Code with Terraform | What IaC is, its advantages, multi-cloud and service-agnostic workflows |
| 2. Terraform fundamentals | Installing and versioning providers, how providers are used, multiple providers, how state is used |
| 3. Core Terraform workflow | write, plan, apply; init, validate, plan, apply, destroy, fmt |
| 4. Terraform configuration | resource vs data, references, variables and outputs, complex types, expressions and functions, dependencies, custom conditions, sensitive data and Vault |
| 5. Terraform modules | Sources, variable scope, using modules, versioning |
| 6. Terraform state management | Local backend, locking, remote backend block, drift and state operations |
| 7. Maintain infrastructure | Import, inspecting state with the CLI, verbose logging |
| 8. HCP Terraform | Creating infrastructure, collaboration and governance, workspaces and projects, integration |
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.
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.
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."
}
}
}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.
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 staleMaintaining 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.
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"
}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
| Week | Objectives | Do |
|---|---|---|
| 1 | 1–4: fundamentals, workflow, configuration | Build 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 |
| 2 | 5–7: modules, state, maintenance | Extract 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 |
| 3 | 8 plus review | Connect 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.