Terraform Certification Prep
Comprehensive guide for the HashiCorp Certified: Terraform Associate (003) exam.
Exam Overview
- Exam ID: HashiCorp Certified: Terraform Associate (003)
- Duration: 60 minutes
- Questions: 57 multiple choice and multiple select
- Passing Score: 70%
- Cost: $70.50 USD
- Format: Online proctored
- Prerequisites: None (recommended: hands-on experience)
9 Exam Domains and Weights
- Understand IaC Concepts (20%)
- Understand Terraform's Purpose (17%)
- Understand Terraform Basics (13%)
- Use Terraform Outside of Core Workflow (8%)
- Interact with Terraform Modules (12%)
- Manage Terraform State (15%)
- Understand Terraform Cloud/Enterprise (8%)
- Read, Generate, and Modify Configurations (15%)
- Understand Terraform Security (12%)
Domain 1: Understand IaC Concepts (20%)
Key Concepts
- Codification: Infrastructure defined in code rather than manual configuration
- Version Control: Track infrastructure changes with Git
- Automation: Reduce manual operations and human error
- Consistency: Reproduce environments reliably
- Scalability: Manage thousands of resources
IaC Approaches
- Declarative (desired state): Terraform, CloudFormation, Ansible
- Imperative (step-by-step): Ansible, Chef, Puppet
Benefits of IaC
- Disaster recovery (rebuild entire infrastructure)
- Environment parity (dev, staging, prod identical)
- Compliance and audit trails
- Self-documentation
- Cost optimization
Best Practices
- Store code in version control
- Code review via pull requests
- Test configurations before production
- Automate deployment via CI/CD
- Document and maintain code quality
Domain 2: Understand Terraform's Purpose (17%)
When to Use Terraform
- Multi-cloud infrastructure management
- Complex, dynamic environments
- Team collaboration on infrastructure
- Infrastructure versioning and auditing
- Rapid environment provisioning
Terraform Advantages vs Alternatives
| Feature | Terraform | CloudFormation | Ansible | Pulumi |
|---|---|---|---|---|
| Multi-cloud | Yes | No | Yes | Yes |
| Language | HCL | YAML/JSON | YAML | Programming |
| State | Explicit | Implicit | Stateless | Explicit |
| Learning curve | Moderate | Steep | Easy | Steep |
Use Cases
- AWS/Azure/GCP multi-cloud: Terraform excels
- Immutable infrastructure: Terraform + Packer
- Complex dependencies: Terraform's dependency graph
- Team environments: Terraform Cloud for collaboration
- Legacy systems: Terraform import for existing resources
Domain 3: Understand Terraform Basics (13%)
Terraform Workflow (Core Workflow)
- Write: Create
.tffiles - Plan:
terraform planshows proposed changes - Apply:
terraform applycreates/modifies resources - Destroy:
terraform destroyremoves resources
Key Files and Directories
main.tf: Primary configurationvariables.tf: Input variablesoutputs.tf: Output valuesterraform.tfvars: Variable values.terraform/: Provider plugins and modules.tfstate: Local state file (don't commit!).gitignore: Exclude sensitive files
Initialization
terraform init
- Downloads provider plugins
- Initializes backend
- Validates configuration
- Sets up .terraform directory
Providers
Plugins enabling Terraform to manage resources on cloud platforms and APIs.
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
Resources vs Data Sources
- Resources: Objects you create and manage
- Data sources: Read-only queries of existing infrastructure
State File
- Tracks deployed resources
- Enables resource updates and deletion
- Must be secured (contains secrets)
- Enable remote backends for teams
- Never commit to Git
Domain 4: Use Terraform Outside of Core Workflow (8%)
terraform console
Interactive REPL for testing expressions:
terraform console
> aws_instance.web.public_ip
> var.region
> data.aws_availability_zones.available.names
terraform graph
Visualizes dependency graph:
terraform graph | dot -Tsvg > graph.svg
terraform taint/untaint
Mark resources for recreation:
terraform taint aws_instance.web
terraform untaint aws_instance.web
terraform apply # Recreates tainted resource
terraform refresh
Update state to match real infrastructure:
terraform refresh
terraform refresh -target="aws_instance.web"
terraform fmt
Auto-format HCL files:
terraform fmt # Format current directory
terraform fmt -recursive # Recursively format
terraform fmt -check # Check without modifying
terraform validate
Check syntax and configuration:
terraform validate
terraform validate -json
Domain 5: Interact with Terraform Modules (12%)
Module Basics
Modules are reusable Terraform packages.
module "vpc" {
source = "./modules/vpc"
vpc_cidr = "10.0.0.0/16"
azs = ["us-east-1a", "us-east-1b"]
}
# Access module outputs
resource "aws_security_group" "app" {
vpc_id = module.vpc.vpc_id
}
Module Sources
- Local:
./modules/vpc - Terraform Registry:
terraform-aws-modules/vpc/aws - Git:
git::https://github.com/example/repo.git - HTTP:
https://example.com/modules.zip - S3:
s3::https://bucket.s3.amazonaws.com/key
Terraform Registry
Public registry at https://registry.terraform.io:
module "rds" {
source = "terraform-aws-modules/rds/aws"
version = "~> 5.0"
# Configuration
}
Module Output Values
Modules expose outputs for composition:
# modules/vpc/outputs.tf
output "vpc_id" {
value = aws_vpc.main.id
}
# root/main.tf
resource "aws_security_group" "web" {
vpc_id = module.vpc.vpc_id # Use module output
}
Module Input Variables
Modules accept input variables:
# modules/vpc/variables.tf
variable "vpc_cidr" {
type = string
}
# root/main.tf
module "vpc" {
source = "./modules/vpc"
vpc_cidr = "10.0.0.0/16"
}
Best Practices
- Use Terraform Registry for proven modules
- Validate module inputs with type constraints
- Document module purpose and usage
- Version modules in registry or Git
- Keep modules focused and reusable
Domain 6: Manage Terraform State (15%)
State File Purpose
- Tracks resource state and metadata
- Enables resource updates
- Maps resource names to cloud IDs
- Contains sensitive data (secrets, passwords)
Local vs Remote State
- Local: Development only (risky for teams)
- Remote: Production standard (S3, Terraform Cloud, etc.)
Remote State Backends
terraform {
backend "s3" {
bucket = "my-state-bucket"
key = "prod/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-locks"
}
}
State Locking
Prevents concurrent modifications via DynamoDB:
# Automatic with DynamoDB
dynamodb_table = "terraform-locks"
During terraform apply:
- Lock entry created in DynamoDB
- Changes applied
- Lock released
State Operations
# Show current state
terraform show
terraform state list
terraform state show aws_instance.web
# Modify state (use carefully)
terraform state mv old_name new_name
terraform state rm aws_instance.deprecated
# Pull remote state locally
terraform state pull > backup.tfstate
# Push local state remotely
terraform state push backup.tfstate
State Security
- Encrypt state in transit (HTTPS, TLS)
- Encrypt state at rest (S3 encryption, KMS)
- Restrict access via IAM policies
- Enable versioning on state backend
- Regular backups
- Never commit to Git
State Sensitivity
Mark sensitive data:
variable "db_password" {
type = string
sensitive = true
}
output "connection_string" {
value = "mysql://admin:${var.db_password}@db:3306/app"
sensitive = true # Not displayed in CLI
}
Domain 7: Understand Terraform Cloud/Enterprise (8%)
Terraform Cloud
SaaS platform for Terraform teams.
Features:
- Remote state management
- VCS integration (GitHub, GitLab, Azure DevOps)
- Runs (plan/apply) with approvals
- Cost estimation
- Sentinel policy as code
- Team management and RBAC
- Private module registry
- Run history and audit logs
Configuration
terraform {
cloud {
organization = "my-org"
workspaces {
name = "production"
}
}
}
Workflows
- VCS-driven: Push to Git → Terraform Cloud triggers plan
- CLI-driven:
terraform applyfrom CLI → runs in Terraform Cloud - API-driven: REST API for programmatic runs
Sentinel Policy as Code
Enforce governance policies:
# policy.sentinel
import "tfplan/v2" as tfplan
deny_large_instances = rule {
all tfplan.resource_changes.aws_instance as _, instances {
all instances[_].change.after.instance_type as instance_type {
instance_type not in ["t2.micro", "t2.small", "t3.micro"]
}
}
}
main = rule {
deny_large_instances
}
Terraform Enterprise
Self-hosted version of Terraform Cloud for on-premises deployments.
Domain 8: Read, Generate, and Modify Configurations (15%)
Dependency Management
Terraform automatically manages explicit and implicit dependencies:
# Explicit: depends_on
resource "aws_instance" "web" {
depends_on = [aws_security_group.web]
}
# Implicit: reference other resources
resource "aws_security_group" "web" {
vpc_id = aws_vpc.main.id # Creates implicit dependency
}
Resource Meta-Arguments
resource "aws_instance" "web" {
# depends_on: explicit dependencies
depends_on = [aws_subnet.public]
# count: create multiple instances
count = var.instance_count
# for_each: create instances from map
for_each = var.instances
# provider: specify provider alias
provider = aws.us-west-2
# lifecycle: control resource behavior
lifecycle {
create_before_destroy = true
}
# timeouts: set operation timeouts
timeouts {
create = "10m"
delete = "10m"
}
}
Expressions and Functions
# Conditionals
var.environment == "prod" ? "t3.large" : "t2.micro"
# Functions
concat(var.list1, var.list2)
merge(map1, map2)
lookup(var.tags, "Environment", "default")
contains(var.allowed_regions, var.region)
# For expressions
[for item in var.items : upper(item)]
{for k, v in var.map : k => upper(v)}
Dynamic Blocks
Generate repetitive blocks:
dynamic "ingress" {
for_each = var.ingress_rules
content {
from_port = ingress.value.port
protocol = ingress.value.protocol
cidr_blocks = ingress.value.cidrs
}
}
Splat Expressions
Get values from multiple resources:
aws_instance.web[*].id # [id1, id2, id3]
aws_instance.web[*].public_ip # [ip1, ip2, ip3]
Domain 9: Understand Terraform Security (12%)
State Security
- Store remotely (S3, Terraform Cloud)
- Enable encryption at rest and in transit
- Restrict access via IAM
- Enable versioning and MFA delete
- Regular backups
Sensitive Data
variable "api_key" {
type = string
sensitive = true # Not logged in console
}
output "db_password" {
value = random_password.db.result
sensitive = true # Not displayed in terraform output
}
Provider Credentials
Never hardcode credentials:
# WRONG
provider "aws" {
access_key = "AKIAIOSFODNN7EXAMPLE"
secret_key = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
}
# RIGHT: Use environment variables or IAM roles
provider "aws" {
region = var.region
# Credentials from environment or assume role
}
Terraform Cloud Security
- Team members and permissions
- API tokens scoped to organizations
- Two-factor authentication (2FA)
- Audit logs
- Run approvals
- Sentinel policies
Backend Security
- Encrypt state bucket
- Block public access
- Enable versioning
- Use IAM policies to restrict access
- Enable bucket logging
Secrets Management
Integrate with secret managers:
# AWS Secrets Manager
data "aws_secretsmanager_secret_version" "db_password" {
secret_id = "prod/db/password"
}
resource "aws_db_instance" "main" {
password = jsondecode(
data.aws_secretsmanager_secret_version.db_password.secret_string
).password
}
# HashiCorp Vault
data "vault_generic_secret" "api_key" {
path = "secret/api/key"
}
resource "aws_instance" "web" {
user_data = templatefile("${path.module}/init.sh", {
api_key = data.vault_generic_secret.api_key.data["key"]
})
}
Code Review and Approval
- Require plan review before apply
- Use Terraform Cloud run approvals
- Code review via pull requests
- Automated compliance checks
Practice Questions (20)
Question 1
You have a local state file and want to migrate to S3 backend. What is the recommended approach?
A) Copy the state file manually to S3
B) Use terraform init with backend configuration
C) Use terraform state push
D) Delete local state and re-apply
Answer: B - terraform init handles state migration automatically.
Question 2
Which of the following is a valid provider source?
A) aws
B) registry.terraform.io/hashicorp/aws
C) hashicorp/aws
D) https://aws-provider.com
Answer: C - Short form with source = "hashicorp/aws" is valid.
Question 3
What does terraform plan -out=tfplan do?
A) Creates a plan and immediately applies it B) Saves the plan to a file for later review/apply C) Plans and outputs results in JSON format D) Destroys resources according to the plan
Answer: B - The -out flag saves the plan for later application.
Question 4
How would you reference an output from a module named vpc?
A) vpc.vpc_id
B) module.vpc.vpc_id
C) var.vpc.vpc_id
D) output.vpc.vpc_id
Answer: B - Module outputs use module.NAME.output_name syntax.
Question 5
Which backend provides state locking via DynamoDB?
A) Local B) Terraform Cloud C) S3 (with DynamoDB table) D) Git
Answer: C - S3 backend supports locking with DynamoDB.
Question 6
What is the purpose of terraform.tfstate.backup?
A) Backup for disaster recovery B) Previous state version (created before each apply) C) Encrypted state file D) For remote backends only
Answer: B - .backup is the previous state version before the last apply.
Question 7
How do you make a variable sensitive so it's not displayed in logs?
A) Use private = true
B) Use sensitive = true
C) Prefix with underscore: _variable
D) Store in Vault instead
Answer: B - The sensitive meta-argument hides the value.
Question 8
What does terraform import aws_instance.web i-1234567890abcdef0 do?
A) Creates a new instance B) Adds existing resource to state file C) Imports Terraform configuration from AWS D) Backs up the resource
Answer: B - terraform import adds an existing resource to state.
Question 9
Which is the correct way to use for_each in a resource?
A) for_each = var.instances (where instances is a list)
B) for_each = var.instances (where instances is a map)
C) for_each = range(5)
D) Both B and C
Answer: D - for_each accepts maps or sets; range() creates a list converted to set.
Question 10
What happens if you use count with a value that changes?
A) Resources are reused with new indices B) Resources are destroyed and recreated C) Error message appears D) Resources shift indices (causing unnecessary replacements)
Answer: D - Changing count value causes index shifts and resource replacement.
Question 11
How do you prevent accidental resource destruction?
A) Use prevent_destroy = true in lifecycle
B) Delete the resource block
C) Set state to read-only
D) Use -protect flag
Answer: A - The prevent_destroy lifecycle argument blocks deletion.
Question 12
What is Terraform Cloud?
A) AWS's infrastructure service B) HashiCorp's SaaS platform for Terraform collaboration C) A free hosting service for state files D) A Terraform plugin marketplace
Answer: B - Terraform Cloud is HashiCorp's managed platform.
Question 13
Which statement about modules is true?
A) Modules cannot have outputs B) Modules can be nested C) Modules require Terraform Cloud D) Modules are only from the registry
Answer: B - Modules can be nested and combined hierarchically.
Question 14
How do you set variable values via CLI?
A) terraform apply region=us-west-2
B) terraform apply -var="region=us-west-2"
C) terraform apply --set region=us-west-2
D) Set environment variables only
Answer: B - Use -var="key=value" to set variables.
Question 15
What is the main advantage of remote state?
A) Faster plan/apply B) Allows team collaboration and locking C) Automatic backups only D) Reduced file size
Answer: B - Remote state enables team workflows and prevents concurrent modifications.
Question 16
How do you reference a data source in Terraform?
A) var.datasource_name
B) data.datasource_type.datasource_name
C) module.datasource_name
D) datasource.name
Answer: B - Data sources are referenced as data.TYPE.NAME.
Question 17
What is the purpose of .gitignore in a Terraform project?
A) Ignore Terraform syntax errors
B) Exclude files from version control (like .tfstate)
C) Ignore module errors
D) Skip validation checks
Answer: B - .gitignore prevents committing sensitive files to Git.
Question 18
Which command formats all Terraform files recursively?
A) terraform fmt .
B) terraform fmt -recursive .
C) terraform format -all
D) terraform init --format
Answer: B - The -recursive flag formats all files in subdirectories.
Question 19
What does Sentinel policy as code do in Terraform Cloud?
A) Encrypts state files B) Enforces governance and compliance policies C) Manages user authentication D) Compresses Terraform configurations
Answer: B - Sentinel enforces policy rules before runs are applied.
Question 20
How do you create an EC2 instance using an implicit dependency?
A) depends_on = [aws_security_group.web]
B) Reference security group: vpc_security_group_ids = [aws_security_group.web.id]
C) Both create implicit dependency
D) Only explicit depends_on works
Answer: B - Referencing a resource creates an implicit dependency automatically.
Study Tips
- Hands-on Practice: Build actual infrastructure with Terraform
- Read Documentation: Review official Terraform docs thoroughly
- Understand State: Deep knowledge of state management is critical
- Module Experience: Create and use modules in real projects
- Command Proficiency: Know all major commands and flags
- Security Focus: Understand secrets, sensitive data, and access control
- Compare Tools: Know Terraform vs CloudFormation vs Pulumi
- Take Practice Tests: Use HashiCorp's official practice exams
- Review Exam Objectives: Spend extra time on high-weight domains
- Time Management: 60 minutes for 57 questions = ~1 minute per question
Resources
- HashiCorp Terraform Docs
- Terraform Associate Exam Guide
- Terraform Registry
- Terraform Cloud Documentation
Good luck on your exam!