Sitemap

HashiCorp Certified: Terraform Associate (003) — Exam Guide (2025 Edition)

14 min readOct 4, 2025

Introduction

Terraform is a powerful Infrastructure as Code (IaC) tool that allows you to define and manage infrastructure using a declarative configuration language. Whether you are preparing for the Terraform Associate Certification or want to master Terraform, this guide provides a comprehensive cheat sheet covering key concepts, commands, best practices, and exam tips.

Terraform Associate Certification Exam Tips

📌 Exam Duration: 60 minutes
📌 Number of Questions: ~57 multiple-choice questions
📌 Passing Score: ~70% (HashiCorp does not publish passing scores; however, in practice many candidates report that **scores ≥ 70%** typically result in a pass.)

📌 Key Topics Covered:

  1. Terraform Basics (Commands, HCL Syntax, Providers)
  2. State Management (Local vs. Remote, Locking, Backends)
  3. HCP Terraform (formerly Terraform Cloud) & Workspaces
  4. Modules & Reusability
  5. Provisioners (Local, Remote, File)
  6. Security Best Practices
  7. Lifecycle Rules & Meta-Arguments
  8. Interpolation & Functions
  9. Terraform Import & Debugging
  10. Managing Infrastructure as Code (IaC)

Study Resources (official first)

Quick starts to focus on:

Courses & Practice (use what fits your style/budget):

Community practice (optional)

Terraform Architecture

Press enter or click to view image in full size

Based on the image, Terraform Architecture consists of the following key components:

1. Terraform Core

  • The central engine that takes infrastructure definitions written in HCL (HashiCorp Configuration Language) and processes them.
  • It reads the Terraform manifest files (.tf), executes plan and apply commands, and manages infrastructure state.

2. Terraform State File (terraform.tfstate)

  • Stores the current state of infrastructure.
  • Helps Terraform determine what changes need to be made.
  • Essential for tracking resources across multiple Terraform runs.

3. Providers

  • Providers act as an interface between Terraform and different cloud platforms.
  • Examples: AWS, Azure, GCP, VMware, OpenShift.
  • They enable Terraform to create, modify, and manage resources in these cloud platforms.

4. Provisioners

  • Provisioners execute scripts or commands on a resource after its creation.
  • Two common types:
  • Remote-exec: Runs commands on remote machines via SSH.
  • Local-exec: Executes scripts on the local machine.

5. Plugins

  • Terraform loads plugins to communicate with providers and execute provisioning logic.
  • Each provider and provisioner has its own plugin.

6. Cloud Service Providers & Platforms

- Cloud providers: AWS, Azure, Google Cloud, VMware
- Platforms / orchestrators: Kubernetes, OpenShift

  • Terraform applies configurations to these platforms using API calls.

Terraform Installation

Windows

  1. Download the binary from Terraform Downloads.
  2. Unzip and move it to a directory in PATH.
  3. Verify installation: terraform version

Linux (Ubuntu/Debian) via Package Manager

# Ubuntu / Debian (recommended)
sudo apt-get update && sudo apt-get install -y gnupg software-properties-common
wget -O- https://apt.releases.hashicorp.com/gpg | \
gpg --dearmor | sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg >/dev/null

echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] \
https://apt.releases.hashicorp.com $(. /etc/os-release && echo $VERSION_CODENAME) main" | \
sudo tee /etc/apt/sources.list.d/hashicorp.list

sudo apt-get update && sudo apt-get install -y terraform
terraform version

macOS (Homebrew)

brew tap hashicorp/tap
brew install hashicorp/tap/terraform

Terraform Workflow

  1. Write Configuration — Define infrastructure using HCL (HashiCorp Configuration Language).
  2. Initializeterraform init
  3. Planterraform plan
  4. Applyterraform apply
  5. Destroyterraform destroy

terraform init

Initialize a Terraform working directory. Downloads provider plugins and prepares the backend.

terraform init
terraform init -upgrade # Upgrade providers to latest version
terraform init -migrate-state # Migrate state to new backend
terraform init -reconfigure # Reconfigure backend ignoring existing configuration

terraform validate

Check Terraform configuration files for syntax errors and internal consistency.

terraform validate
terraform validate -json # Output in JSON format

terraform plan

Preview the changes Terraform will make to the infrastructure without applying them.

terraform plan
terraform plan -out=tfplan # Save plan to a file
terraform plan -var="instance_type=t2.micro"
terraform plan -target=aws_instance.example # Plan for specific resource only
terraform plan -refresh-only # Only refresh state, don't plan changes

terraform apply

Apply the changes and provision/modify the infrastructure.

terraform apply
terraform apply tfplan # Apply a saved plan
terraform apply -auto-approve # Skip interactive approval
terraform apply -replace="aws_instance.example" # Force replace a specific resource
terraform apply -target=aws_instance.example # Apply only specific resource
terraform apply -refresh-only # Only update state to match real-world

terraform destroy

Destroy all infrastructure managed by Terraform.

terraform destroy
terraform destroy -auto-approve
terraform destroy -target=aws_instance.example # Destroy only specific resource

💡 Exam Tip: Always run terraform plan before terraform apply to preview changes and avoid unexpected results.

Terraform File Structure

  • Main Configuration: main.tf
  • Variables: variables.tf
  • Outputs: outputs.tf
  • State File: terraform.tfstate
  • Backend Configuration: backend.tf
  • Terraform Lock File: .terraform.lock.hcl
  • Providers: provider.tf

💡 Exam Tip: Organizing Terraform files properly helps in maintaining clean and scalable infrastructure.

Terraform Providers

Terraform uses providers to interact with different services.

Common Providers

  • AWS: terraform-provider-aws
  • Azure: terraform-provider-azurerm
  • Google Cloud: terraform-provider-google
  • Kubernetes: terraform-provider-kubernetes

Example AWS Provider

terraform {
required_providers {
aws = { # provider local name
source = "hashicorp/aws" # global and unique source address
version = ">= 5.0, < 7.0"
}
}
}
provider "aws" {
region = "us-west-2"
}

💡 Exam Tip: Always specify the provider and region explicitly in your configurations to avoid unintended behaviors.

  • Providers can be written by individuals
  • Providers can be maintained by a community of users
  • Some providers are maintained by HashiCorp
  • Major cloud vendors and non-cloud vendors can write, maintain, or collaborate on Terraform providers

Terraform Backends (State Management)

Terraform backend is used to store and manage Terraform state files.

Local Backend Example:

terraform {
backend "local" {}
}

Remote Backend (AWS S3 + DynamoDB Locking)

terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "prod/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-lock"
}
}
  • dynamodb_table is used for state locking.
  • Use remote backends like AWS S3 or HashiCorp Terraform Cloud for storing the state.

💡 Exam Tip: Using remote backends allows collaboration and prevents data loss.

💡 State Locking: Prevents multiple users from making conflicting changes.

Terraform State Commands

The state is stored by default in a local file named “terraform.tfstate”

terraform state list

List all resources in the state file.

terraform state list
terraform state list aws_instance.* # Filter by resource type

terraform state show

Show detailed information about a specific resource in the state.

terraform state show aws_instance.example

terraform state mv

Move or rename a resource in the state file.

terraform state mv aws_instance.old aws_instance.new
terraform state mv aws_instance.example module.ec2.aws_instance.example

terraform state rm

Remove a resource from the state file without destroying it.

terraform state rm aws_instance.example

terraform state pull

Download and output the current state file.

terraform state pull > backup.tfstate

terraform state push

Upload a local state file to the remote backend.

terraform state push terraform.tfstate

terraform state replace-provider

Replace the provider for resources in the state.

terraform state replace-provider "registry.terraform.io/-/aws" "registry.terraform.io/hashicorp/aws"terraform state replace-provider registry.terraform.io/hashicorp/aws registry.terraform.io/hashicorp/aws

💡 Exam Tip: The terraform state command is essential for troubleshooting, renaming resources, and manually removing resources from the state file without destroying them.

Import and Output Commands

terraform import

Used to bring existing infrastructure under Terraform management.

terraform import aws_instance.example i-1234567890abcdef0
terraform import 'module.vpc.aws_vpc.main' vpc-12345678
  • After import, Terraform state knows about the resource but configuration must be written manually.

💡 Note: Terraform 1.5+ supports declarative import blocks:

import {
to = aws_instance.example
id = "i-1234567890abcdef0"
}

terraform output

Display output values from your Terraform configuration.

terraform output                    # Show all outputs
terraform output instance_ip # Show specific output
terraform output -json # Output in JSON format
terraform output -raw instance_ip # Raw output without quotes (useful for scripts)

💡 Exam Tip: The terraform import command does not generate configuration files; you must manually define the imported resources in your Terraform code.

Terraform Locking Mechanism

  • Ensures only one process modifies state at a time.
  • Enabled for Remote Backends (e.g., S3 with DynamoDB).
  • Locking Error Example:
Error: Error locking state: Error acquiring state lock
  • Solution: Manually unlock:
terraform force-unlock <LOCK_ID>

💡 Exam Tip: Always enable state locking in a remote backend (such as AWS DynamoDB) to prevent multiple users from modifying the state file simultaneously.

Workspaces

Create a new workspace:

terraform workspace new <name>

Select a workspace:

terraform workspace select <name>

List all workspaces:

terraform workspace list

Delete an existing workspace:

terraform workspace delete staging

Show the current workspace name:

terraform workspace show

💡 Exam Tip: > Tip: Workspaces separate state, not configuration. They can help for lightweight env splits, but many teams prefer separate folders/repos or distinct HCP Terraform workspaces per environment for stronger isolation.

Formatting and Validation Commands

terraform fmt

Format Terraform configuration files to a canonical style.

terraform fmt                    # Format files in current directory
terraform fmt -recursive # Format all files in subdirectories
terraform fmt -check # Check if files are formatted (useful in CI/CD)
terraform fmt -diff # Show formatting changes

terraform console

Interactive console for evaluating Terraform expressions.

terraform console
# Then you can test expressions:
> var.instance_type
> aws_instance.example.id
> length(var.availability_zones)

⚠️ Deprecated Commands (Do NOT Use)

terraform taint ❌ DEPRECATED

Old way (before Terraform 0.15.2):

terraform taint aws_instance.example

New way (Terraform 0.15.2+):

terraform apply -replace="aws_instance.example"

terraform untaint ❌ DEPRECATED

No longer needed. Resources are not tainted anymore; use -replace flag instead.

terraform refresh ❌ DEPRECATED

Old way:

terraform refresh

New way (Terraform 0.15.4+):

terraform apply -refresh-only
# or during plan
terraform plan -refresh-only

Note: `terraform refresh` is deprecated; use `-refresh-only` with plan/apply.

Environment Variables for Terraform Commands

# Enable detailed logging
export TF_LOG=TRACE # TRACE, DEBUG, INFO, WARN, ERROR
export TF_LOG_PATH=./terraform.log

# Input variables via environment
export TF_VAR_instance_type=t2.micro
export TF_VAR_region=us-east-1

# Configure CLI behavior
export TF_CLI_ARGS_plan="-out=tfplan"
export TF_CLI_ARGS_apply="-auto-approve"

# Disable color output
export TF_NO_COLOR=1

# Custom data directory
export TF_DATA_DIR=./.terraform-custom

Command Combinations & Best Practices

Safe Apply Workflow

terraform fmt -recursive
terraform validate
terraform plan -out=tfplan
terraform show tfplan
terraform apply tfplan

State Backup Before Dangerous Operations

terraform state pull > backup-$(date +%Y%m%d-%H%M%S).tfstate
terraform state rm aws_instance.example

Check What Will Be Destroyed

terraform plan -destroy
terraform destroy -target=aws_instance.example # Selective destroy

Working with Multiple Environments

terraform workspace new production
terraform plan -var-file="production.tfvars"
terraform apply -var-file="production.tfvars"

💡 Exam Tips

  • Always run terraform plan before terraform apply to preview changes
  • Use -out flag with plan to save and review changes before applying
  • Understand the difference between terraform refresh (deprecated) and terraform apply -refresh-only
  • Know when to use -replace instead of the old taint command
  • State commands (state mv, state rm) are crucial for refactoring without destroying resources
  • Workspaces separate state, not configuration; for long-lived environments prefer one workspace per environment (or separate folders/repos).
  • terraform fmt should be part of your CI/CD pipeline with -check flag
  • Remote state locking is automatically handled by backends like S3+DynamoDB
  • terraform console is extremely useful for testing expressions and functions interactively

Terraform Resource Meta-Arguments

depends_on

Ensures that a resource is created only after another resource is available.

resource "aws_instance" "web" {
depends_on = [aws_s3_bucket.example]
}

Use Case: Ensures the EC2 instance is created only after the S3 bucket exists.

count (Used for creating multiple resources)

resource "aws_instance" "example" {
count = 3
ami = "ami-123456"
}

for_each (For dynamic resource creation)

variable "instances" {
type = map(object({
ami = string
}))
default = {
instance1 = { ami = "ami-123456" }
instance2 = { ami = "ami-654321" }
}
}
resource "aws_instance" "example" {
for_each = var.instances
ami = each.value["ami"]
}

lifecycle (Managing resource behavior)

resource "aws_instance" "example" {
lifecycle {
prevent_destroy = true # Prevents accidental deletion
}
}

💡 Exam Tips:

  • Use depends_on only when needed; Terraform manages dependencies automatically.
  • Use count for simple replication and for_each for dynamic resources.
  • lifecycle helps prevent unintended resource changes or destruction.
  • Avoid hardcoded values; use variables for flexibility.

Data Sources

Data sources in Terraform allow you to query and retrieve information from external systems like AWS, Azure, or other Terraform state files. This helps in using dynamically fetched data instead of hardcoded values.

Example: Fetching AWS AMI ID

data "aws_ami" "latest" {
most_recent = true
owners = ["amazon"] # ensure official images

filter {
name = "name"
values = ["amzn2-ami-hvm*"]
}
}

Use in Resource:

resource "aws_instance" "example" {
ami = data.aws_ami.latest.id
}

Example: Retrieving AWS VPC ID

data "aws_vpc" "default" {
default = true
}
resource "aws_subnet" "example" {
vpc_id = data.aws_vpc.default.id
}

Example: Using Terraform State Data Source

You can reference resources from another Terraform state file:

data "terraform_remote_state" "network" {
backend = "s3"
config = {
bucket = "my-terraform-state"
key = "network/terraform.tfstate"
region = "us-east-1"
}
}
resource "aws_instance" "example" {
vpc_security_group_ids = [data.terraform_remote_state.network.outputs.security_group_id]
}

💡 Exam Tip: Terraform data sources allow you to fetch external information dynamically, enabling your configuration to use the latest values without hardcoding.

Dynamic Blocks

Terraform supports loops inside resource blocks using dynamic blocks:

resource "aws_security_group" "example" {
dynamic "ingress" {
for_each = var.allowed_ports
content {
from_port = ingress.value
to_port = ingress.value
protocol = "tcp"
}
}
}

Terraform Variables and Data Types

  • String: "example"
  • Number: 42
  • List: [1, 2, 3]
  • Map: { key = "value" }
  • Boolean: true or false
  • Tuple: [1, "hello", true]
  • Object: { name = "John", age = 30 }
  • Sensitive Variables: sensitive = true (Hides sensitive data in Terraform output)

💡 Exam Tip: Use variable validation to enforce constraints on input variables. Avoid hardcoding values and use variable files (.tfvars).

Terraform Locals

Locals define reusable values within a module:

locals {
common_tags = {
Environment = "dev"
Owner = "team"
}
}
resource "aws_vpc" "main" {
tags = local.common_tags
}

Terraform Functions

Math Functions

sum([1, 2, 3])    # Output: 6
max(3, 9, 2) # Output: 9
min(3, 9, 2) # Output: 2

String Functions

upper("hello")    # Output: "HELLO"
lower("HELLO") # Output: "hello"
replace("hello", "h", "y") # Output: "yello"

Collection Functions

length(["a", "b", "c"])  # Output: 3
contains(["a", "b", "c"], "b") # Output: true

Date & Time Functions

formatdate("YYYY-MM-DD", timestamp())

💡 Exam Tip: Terraform functions help manipulate data dynamically. Ensure you understand how to use them for automation and resource interpolation.

Interpolation

String Interpolation:

"Hello, ${var.name}!"

Attribute Interpolation:

aws_instance.example.id

File Interpolation:

file("${path.module}/config.json")

Length Function:

length(var.list)

Conditional Logic & Loops

If Expression:

condition ? true_value : false_value

For Loop in List:

[for element in var.list : element * 2]

For Loop in Map:

{ for k, v in var.map : k => v * 2 }

Count:

resource "aws_instance" "example" {
count = 3
ami = "ami-123456"
}

💡 Exam Tip: Conditional logic and loops help optimize infrastructure configurations by reducing redundant code.

Splat Expressions

Used to extract values from lists of objects.

# Splat / collection extraction
# From a list of instances, collect all public IPs:
output "instance_public_ips" {
value = aws_instance.web[*].public_ip
}

Terraform Modules

Declare a Module:

module "name" {
source = "path/to/module"
}

Define Input Variables in Modules:

variable "instance_type" { type = string }

Expose Output Values from Modules:

output "instance_id" {
value = aws_instance.example.id
}

💡 Exam Tip: Use modules to structure your Terraform code for reusability and maintainability.

Lifecycle Management

Terraform lifecycle meta-argument helps control resource behavior, preventing unintended deletions, ensuring seamless updates, and ignoring specific changes to maintain stability.

Prevent Destroy:

resource "aws_instance" "example" {
lifecycle {
prevent_destroy = true
}
}

Create Before Destroy:

resource "aws_instance" "example" {
lifecycle {
create_before_destroy = true
}
}

Ignore Changes:

resource "aws_instance" "example" {
lifecycle {
ignore_changes = [tags]
}
}

💡 Exam Tips:

  • Use prevent_destroy for critical resources to avoid accidental deletion.
  • Use create_before_destroy for zero-downtime changes when replacing resources.
  • Use ignore_changes to avoid unnecessary updates when external systems modify resources.
  • Terraform’s lifecycle should be used carefully as it impacts state management and updates.

Provisioners

Local Exec Provisioner:

resource "null_resource" "example" {
provisioner "local-exec" {
command = "echo 'Resource Created!' > log.txt"
}
}

Remote Exec Provisioner:

resource "aws_instance" "example" {
ami = "ami-12345678"
instance_type = "t2.micro"
  connection {
type = "ssh"
user = "ubuntu"
private_key = file("~/.ssh/id_rsa")
host = self.public_ip
}
provisioner "remote-exec" {
inline = [
"sudo apt update",
"sudo apt install -y nginx"
]
}
}

Using a Script with Remote Exec

resource "aws_instance" "example" {
ami = "ami-12345678"
instance_type = "t2.micro"
connection {
type = "ssh"
user = "ubuntu"
private_key = file("~/.ssh/id_rsa")
host = self.public_ip
}
provisioner "remote-exec" {
script = "install_nginx.sh"
}
}

File Provisioner:

resource "aws_instance" "example" {
ami = "ami-12345678"
instance_type = "t2.micro"
  connection {
type = "ssh"
user = "ubuntu"
private_key = file("~/.ssh/id_rsa")
host = self.public_ip
}
provisioner "file" {
source = "config.cfg"
destination = "/home/ubuntu/config.cfg"
}
}

💡 Exam Tip: Terraform provisioners should be used as a last resort; prefer built-in cloud-init, user_data, or configuration management tools for better automation.

Debugging

Enable Debug Logs:

export TF_LOG=DEBUG
terraform apply

Logging to a File:

export TF_LOG_PATH="terraform.log"

💡 Exam Tip: Debug logs help troubleshoot Terraform execution errors and state inconsistencies.

HCP Terraform (formerly Terraform Cloud)

HCP Terraform is HashiCorp’s managed service that provides secure state management, team collaboration, governance, and automation for Terraform workflows.

Press enter or click to view image in full size

HCP Terraform hierarchy. An Organization contains Projects, and each Project contains one or more Workspaces where runs and state are managed. Settings (VCS connections, variables, policies, health checks) can be applied at the organization, project, or workspace level.

Why Use HCP Terraform?

Remote State Management

  • Eliminates the risk of local state loss
  • Enforces state consistency with locking and remote backends

Secure & Scalable Collaboration

  • Team-based access control with RBAC (Role-Based Access Control).
  • Allows multiple team members to work on Terraform without conflicts.
  • Stores sensitive data securely via Terraform Cloud Variables & Workspaces.

Remote Execution & Automation

  • Runs Terraform plans and applies in the cloud, reducing dependency on local machines.
  • Supports VCS (Version Control System) integration (GitHub, GitLab, Bitbucket).
  • Automatically triggers Terraform runs on pull requests or code changes.

Policy Enforcement with Sentinel

  • Enforces security, cost, and compliance rules before Terraform apply.
  • Example: Prevent provisioning expensive instance types.

Private Module Registry

  • Allows teams to publish and reuse Terraform modules securely.
  • Helps standardize infrastructure across the organization.

Drift Detection & Monitoring

  • HCP Terraform can detect when infrastructure has changed outside of Terraform
  • Uses health assessments to continuously check for drift (Plus tier and above)
  • Notifications can be configured when drift is detected
  • Helps identify unauthorized or unexpected infrastructure changes

Multi-Cloud Deployment & Integration

  • Works across AWS, Azure, GCP, Kubernetes, and private clouds.
  • Integrates with Terraform Enterprise for on-premises use cases.
  • Store and manage your Terraform state remotely.
  • Collaborate with team members and apply infrastructure changes using Terraform Cloud.
  • Enable remote execution to apply configurations without local execution.

Example: HCP Terraform Configuration

terraform {
cloud {
organization = "my-org"
workspaces {
name = "prod-environment"
}
}
}

HCP Terraform Authentication

terraform login
terraform logout

💡 Exam Tips:

  • HCP Terraform replaces the old “Terraform Cloud” branding.
  • Remote state + remote runs + policies + VCS integration are core exam points.
  • Sentinel policies evaluate before apply; failed policies block the run.
  • Workspaces are a unit of state/run history; use separate workspaces per environment.

Terraform Security Best Practices

✅ Use Remote Backend for State Storage
✅ Enable State Locking (DynamoDB for AWS)
✅ Never Hardcode Secrets (Use AWS SSM, Vault, or Environment Variables)
✅ Use IAM Roles for Authentication
✅ Restrict Access to the State File
✅ Enable Encryption for Backend Storage

Conclusion

Terraform is an essential tool for modern infrastructure automation, and mastering its fundamentals will greatly enhance your DevOps and cloud engineering skills. Whether you are studying for the Terraform Associate Exam or looking to optimize your workflow, this cheat sheet provides a solid foundation for Terraform proficiency.

🚀 Good luck with your Terraform certification and infrastructure automation journey!

--

--

Responses (1)