Live
Handling Faster Code, Token Spikes, and Agent Guardrails in LLM ProductionAdding Cloudflare Web Search to Agents SDK: Direct Web Queries for Your Durable ObjectsWorkers Observability Events via MCP: Real‑Time Issue Delivery to WebhooksMultilingual Agent Kit Adds Go, Java, Kotlin, and TypeScript SupportScaling AI Agent Swarms: Architecture and Ops Implications for EngineersAnonymous authentication for organization‑level Dependabot registries: practical impactCloudflare Queues add immutable jurisdiction controls for data residencyOpen AI Factory Architecture: NVIDIA’s MGX 1.2 Rack Design and New DSX Tooling Arrive at OCPHandling Faster Code, Token Spikes, and Agent Guardrails in LLM ProductionAdding Cloudflare Web Search to Agents SDK: Direct Web Queries for Your Durable ObjectsWorkers Observability Events via MCP: Real‑Time Issue Delivery to WebhooksMultilingual Agent Kit Adds Go, Java, Kotlin, and TypeScript SupportScaling AI Agent Swarms: Architecture and Ops Implications for EngineersAnonymous authentication for organization‑level Dependabot registries: practical impactCloudflare Queues add immutable jurisdiction controls for data residencyOpen AI Factory Architecture: NVIDIA’s MGX 1.2 Rack Design and New DSX Tooling Arrive at OCP
HashiCorp

Terraform Complete Guide: Infrastructure as Code from Scratch

Overview

This comprehensive tutorial covers Terraform fundamentals essential for building, managing, and scaling infrastructure as code. You'll learn to write declarative infrastructure configurations, manage state files, and deploy resources across cloud providers.

What This Tutorial Covers:

  • Terraform installation and workspace setup
  • Core HCL syntax and resource declarations
  • State management and backend configuration
  • Variables, outputs, and modules
  • Best practices for production environments

Prerequisites:

  • Basic cloud computing knowledge (AWS, Azure, or GCP)
  • Familiarity with command-line interfaces
  • Understanding of infrastructure concepts (compute, networking, storage)
  • Git version control basics

Why This Matters for HashiCorp Certified Terraform Associate: The certification validates your ability to manage infrastructure with Terraform, a critical skill for DevOps engineers. This guide covers 70% of exam content, focusing on practical implementation rather than theory.

Getting Started

Installation and Setup

First, install Terraform on your system. This example uses Linux/macOS:

#!/bin/bash
# Download and install Terraform
wget https://releases.hashicorp.com/terraform/1.6.0/terraform_1.6.0_linux_amd64.zip
unzip terraform_1.6.0_linux_amd64.zip
sudo mv terraform /usr/local/bin/

# Verify installation
terraform version

For Windows users, download the executable directly from releases.hashicorp.com and add to PATH.

Initialize Your First Project

# Create project directory
mkdir terraform-project
cd terraform-project

# Initialize Terraform (creates .terraform directory)
terraform init

Create your first configuration file named main.tf:

terraform {
  required_version = '>= 1.0'
  required_providers {
    aws = {
      source  = 'hashicorp/aws'
      version = '~> 5.0'
    }
  }
}

provider 'aws' {
  region = 'us-east-1'
}

resource 'aws_instance' 'web_server' {
  ami           = 'ami-0c55b159cbfafe1f0'
  instance_type = 't3.micro'

  tags = {
    Name = 'MyWebServer'
  }
}

Core Concepts: Resources and Providers

Understanding Providers

Providers are plugins that enable Terraform to interact with cloud platforms. Each provider manages resources specific to that platform. The provider block configures authentication and default settings.

# AWS Provider example with explicit credentials
provider 'aws' {
  region     = 'us-west-2'
  access_key = var.aws_access_key
  secret_key = var.aws_secret_key
}

# Multiple provider instances
provider 'aws' {
  alias  = 'secondary'
  region = 'eu-west-1'
}

Resource Declaration

Resources are the fundamental building blocks. Each resource block declares a specific infrastructure component:

resource 'resource_type' 'resource_name' {
  argument1 = 'value1'
  argument2 = 'value2'
}

# Real example: Create S3 bucket
resource 'aws_s3_bucket' 'app_bucket' {
  bucket = 'my-unique-app-bucket-2024'
}

# Add versioning to the bucket
resource 'aws_s3_bucket_versioning' 'app_versioning' {
  bucket = aws_s3_bucket.app_bucket.id

  versioning_configuration {
    status = 'Enabled'
  }
}

Common Pitfall: Resource names in Terraform (the name after the resource type) are logical identifiers, not the actual AWS resource name. The bucket argument is what creates the actual S3 bucket name in AWS.

State Management and Variables

Understanding Terraform State

State files track your infrastructure. Terraform stores state in terraform.tfstate by default. For production, use remote backends like S3 to enable team collaboration:

terraform {
  backend 's3' {
    bucket         = 'terraform-state-bucket'
    key            = 'prod/terraform.tfstate'
    region         = 'us-east-1'
    encrypt        = true
    dynamodb_table = 'terraform-locks'
  }
}

# Initialize with backend
terraform init

# View state contents
terraform state list
terraform state show aws_instance.web_server

Variables and Outputs

Create a variables.tf file for input variables:

variable 'environment' {
  type        = string
  default     = 'dev'
  description = 'Environment name'

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

variable 'instance_count' {
  type        = number
  default     = 1
  description = 'Number of EC2 instances'
}

variable 'tags' {
  type = map(string)
  default = {
    Owner = 'CloudNinjas'
    Team  = 'DevOps'
  }
}

Create outputs.tf to expose values:

output 'instance_id' {
  value       = aws_instance.web_server.id
  description = 'ID of the EC2 instance'
}

output 'instance_ip' {
  value       = aws_instance.web_server.public_ip
  description = 'Public IP address'
  sensitive   = false
}

Pass variables using terraform.tfvars:

environment   = 'prod'
instance_count = 3
tags = {
  Owner      = 'CloudNinjas'
  Team       = 'DevOps'
  CostCenter = '12345'
}

Advanced Patterns: Modules and Functions

Creating Reusable Modules

Modules encapsulate infrastructure patterns. Create a directory structure:

modules/
  vpc/
    main.tf
    variables.tf
    outputs.tf

Module main.tf:

resource 'aws_vpc' 'network' {
  cidr_block           = var.cidr_block
  enable_dns_hostnames = true

  tags = {
    Name = var.vpc_name
  }
}

resource 'aws_subnet' 'public' {
  vpc_id            = aws_vpc.network.id
  cidr_block        = var.subnet_cidr
  availability_zone = var.availability_zone

  tags = {
    Name = '${var.vpc_name}-public-subnet'
  }
}

Use the module in your root configuration:

module 'vpc' {
  source = './modules/vpc'

  vpc_name           = 'production-vpc'
  cidr_block         = '10.0.0.0/16'
  subnet_cidr        = '10.0.1.0/24'
  availability_zone  = 'us-east-1a'
}

# Reference module outputs
resource 'aws_instance' 'app' {
  subnet_id      = module.vpc.subnet_id
  instance_type  = 't3.micro'
  ami            = 'ami-0c55b159cbfafe1f0'
}

Built-in Functions and Expressions

# String functions
locals {
  environment_name = lower(var.environment)
  resource_prefix  = join('-', ['app', local.environment_name])
}

# Collection functions
resource 'aws_instance' 'servers' {
  count         = length(var.availability_zones)
  ami           = var.ami_id
  instance_type = var.instance_type
  
  availability_zone = var.availability_zones[count.index]

  tags = {
    Name = '${local.resource_prefix}-${count.index + 1}'
  }
}

# Conditional logic
resource 'aws_eip' 'web' {
  count    = var.allocate_eip ? 1 : 0
  instance = aws_instance.servers[0].id
  domain   = 'vpc'
}

Exam Tips for HashiCorp Certified Terraform Associate

Key Concepts That Appear on the Exam:

  • State Management: Understand terraform.tfstate, remote backends, and state locking with DynamoDB
  • Lifecycle Rules: Know create_before_destroy, prevent_destroy, and ignore_changes
  • Workspaces: Use terraform workspace list, create, select for managing multiple environments
  • Import: Use terraform import aws_instance.example i-1234567890 to bring existing resources under Terraform management
  • Data Sources: Fetch existing infrastructure without creating resources

Common Exam Scenarios:

# Scenario 1: Import existing resource
terraform import 'aws_instance.legacy' 'i-0abcd1234efgh5678'

# Scenario 2: Prevent accidental destruction
resource 'aws_db_instance' 'production' {
  lifecycle {
    prevent_destroy = true
  }
}

# Scenario 3: Use data source to reference existing VPC
data 'aws_vpc' 'default' {
  default = true
}

resource 'aws_security_group' 'app' {
  vpc_id = data.aws_vpc.default.id
}

# Scenario 4: Workspace for environment isolation
terraform workspace new staging
terraform workspace select staging
terraform apply

Quick Reference Commands:

# Validation and formatting
terraform validate
terraform fmt -recursive

# Plan and apply
terraform plan -out=tfplan
terraform apply tfplan

# Debugging
terraform plan -var-file=prod.tfvars
TF_LOG=DEBUG terraform apply

# Cleanup
terraform destroy -auto-approve
terraform state rm aws_instance.old_server

Summary

Key Takeaways:

  • Terraform uses declarative syntax in HCL to define infrastructure as code
  • State files are critical—always use remote backends in production
  • Modules enable code reuse and organizational scalability
  • Variables and outputs make configurations flexible and portable
  • Master plan, apply, and destroy commands for exam success

Next Steps:

  1. Practice with AWS free tier resources
  2. Build a three-tier architecture module (VPC, compute, database)
  3. Set up S3 backend with state locking
  4. Review HashiCorp's official study guide
  5. Take practice exams to assess readiness

For deeper certification preparation, explore our HashiCorp Certified Terraform Associate Study Guide and hands-on labs at CloudNinjas.ca.