INFRASTRUCTURE
AS CODE

// Your cloud, version controlled.

SERVERS SHOULD BE LIKE CASSETTES.

Provisioning infrastructure manually is error-prone and impossible to reproduce. Terraform treats your infrastructure as code—version it, review it, and deploy it automatically.

WHY TERRAFORM

Terraform uses a declarative approach. You define what you want, not how to get there. It figures out the right order, handles dependencies, and creates a plan before making changes.

ONE CODEBASE, ANY CLOUD.

START PROVISIONING →

// The Infrastructure Path

12 lessons. Complete Terraform mastery.

LESSON 01

Introduction to Terraform

What is IaC, how Terraform works, and why it matters

Beginner
LESSON 02

Installing & Configuring

Installing Terraform, providers, and authentication

Beginner
LESSON 03

Resources & Data Sources

Creating resources and querying existing infrastructure

Beginner
LESSON 04

Variables & Outputs

Making configurations flexible and reusable

Intermediate
LESSON 05

State Management

How Terraform tracks resources and remote state

Intermediate
LESSON 06

Modules

Organizing and reusing infrastructure code

Intermediate
LESSON 07

Workspaces

Managing multiple environments (dev, staging, prod)

Intermediate
LESSON 08

Provisioners

Running scripts on created resources

Intermediate
LESSON 09

Terraform in CI/CD

Automating Terraform in your pipelines

Advanced
LESSON 10

Testing & Validation

Terratest, sentinel, and infrastructure testing

Advanced
LESSON 11

Multi-Cloud Patterns

Managing AWS, GCP, Azure with single config

Advanced
LESSON 12

Enterprise Patterns

Policy as Code, Terragrunt, and scaling Terraform

Advanced

// Why Terraform

Terraform is the industry standard for infrastructure as code. It supports over 1000 providers and works across all major cloud platforms.

What you'll master: AWS, GCP, Azure provisioning, state management, modules, workspaces, and enterprise patterns. By the end, you'll provision entire environments with a single command.

Define once, deploy anywhere.

// Lesson 1: Introduction to Terraform

×

What is Infrastructure as Code?

IaC is the practice of managing infrastructure through code rather than manual processes. Your servers, networks, and databases are defined in configuration files that can be versioned, reviewed, and automated.

How Terraform Works

# Terraform uses a declarative approach
# You define the desired state, not the steps

resource "aws_instance" "web" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t3.micro"
}

Terraform Workflow

1. Write   → Define infrastructure in .tf files
2. Plan    → Terraform shows what will change
3. Apply   → Terraform makes the changes
4. Repeat  → Infrastructure evolves with code

Why Terraform?

  • Declarative: Define what you want, not how to get it
  • Provider ecosystem: 1000+ providers for AWS, GCP, Azure, etc.
  • State: Tracks what it's created
  • Plan: See changes before applying

// Knowledge Check

What type of approach does Terraform use?

Hint: Define the ??? state

What command shows what Terraform will change?

Hint: terraform ???

Show Answers

Answers

  1. declarative
  2. plan

// Lesson 2: Installing & Configuring

×

Installing Terraform

# macOS with Homebrew
brew install terraform

# Linux - download binary
wget https://releases.hashicorp.com/terraform/1.7.0/terraform_1.7.0_linux_amd64.zip
unzip terraform_1.7.0_linux_amd64.zip
sudo mv terraform /usr/local/bin/

# Verify installation
terraform --version

Provider Configuration

# main.tf
terraform {
  required_version = ">= 1.0"
  
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = "us-east-1"
  
  # Can use environment variables
  # AWS_ACCESS_KEY_ID
  # AWS_SECRET_ACCESS_KEY
}

Initializing Terraform

# Initialize providers and modules
terraform init

# Downloaded providers are stored in .terraform/

// Knowledge Check

What command initializes Terraform?

Hint: terraform ???

Where are Terraform providers downloaded?

Hint: Hidden folder

Show Answers

Answers

  1. init
  2. .terraform

// Lesson 3: Resources & Data Sources

×

Creating Resources

resource "aws_instance" "web" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t3.micro"
  
  tags = {
    Name = "web-server"
    Environment = "production"
  }
}

resource "aws_security_group" "web" {
  name = "web-sg"
  
  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

Data Sources

# Query existing infrastructure without creating it
data "aws_ami" "ubuntu" {
  most_recent = true
  
  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-*-22.04-amd64-server-*"]
  }
  
  owners = ["099720109477"] # Canonical
}

# Use the data source
resource "aws_instance" "server" {
  ami           = data.aws_ami.ubuntu.id
  instance_type = "t3.micro"
}

Resource Dependencies

# Terraform automatically handles dependencies
resource "aws_instance" "web" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t3.micro"
  # This depends on aws_security_group.web implicitly
}

resource "aws_security_group" "web" {
  name = "web-sg"
}

// Knowledge Check

What block queries existing infrastructure?

Hint: ??? source

What block creates new infrastructure?

Hint: ??? block

Show Answers

Answers

  1. data
  2. resource

// Lesson 4: Variables & Outputs

×

Input Variables

# variables.tf
variable "instance_type" {
  type        = string
  default     = "t3.micro"
  description = "EC2 instance type"
}

variable "environment" {
  type        = string
  description = "Environment name"
  
  validation {
    condition     = contains(["dev", "staging", "prod"], var.environment)
    error_message = "Must be dev, staging, or prod"
  }
}

variable "tags" {
  type        = map(string)
  default     = {}
  description = "Tags to apply to resources"
}

Using Variables

# Using variables in resources
resource "aws_instance" "web" {
  instance_type = var.instance_type
  ami           = "ami-0c55b159cbfafe1f0"
  
  tags = merge(var.tags, {
    Environment = var.environment
  })
}

Output Values

# outputs.tf
output "instance_id" {
  description = "ID of the EC2 instance"
  value       = aws_instance.web.id
  sensitive   = false
}

output "instance_public_ip" {
  description = "Public IP address"
  value       = aws_instance.web.public_ip
}

// Knowledge Check

What block defines configurable values?

Hint: ??? block

What exposes resource values to the user?

Hint: ??? block

Show Answers

Answers

  1. variable
  2. output

// Lesson 5: State Management

×

How State Works

Terraform uses state to map real-world resources to your configuration. It tracks resource IDs and properties so it knows what to update or delete.

Local State

# Default - stored in terraform.tfstate
# Not recommended for teams

Remote State

# Configure remote state in S3
terraform {
  backend "s3" {
    bucket         = "my-terraform-state"
    key            = "prod/terraform.tfstate"
    region         = "us-east-1"
    encrypt        = true
    dynamodb_table = "terraform-locks"
  }
}

State Locking

# DynamoDB table for state locking
# Prevents concurrent modifications

resource "aws_dynamodb_table" "terraform_locks" {
  name         = "terraform-locks"
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = "LockID"
  
  attribute {
    name = "LockID"
    type = "S"
  }
}

State Commands

terraform show                # Show current state
terraform state list         # List resources
terraform state show RESOURCE # Show resource details
terraform state mv           # Move resource
terraform state rm           # Remove from state

// Knowledge Check

Where does Terraform store resource mapping?

Hint: terraform.???

What prevents concurrent Terraform runs?

Hint: State ???

Show Answers

Answers

  1. state
  2. locking

// Lesson 6: Modules

×

Why Use Modules?

Modules are reusable Terraform configurations. They let you group resources, hide complexity, and share infrastructure patterns.

Creating a Module

# modules/ec2/main.tf
variable "instance_type" {
  type    = string
  default = "t3.micro"
}

variable "name" {
  type = string
}

resource "aws_instance" "this" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = var.instance_type
  
  tags = {
    Name = var.name
  }
}

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

Using a Module

# main.tf
module "web_server" {
  source = "./modules/ec2"
  
  instance_type = "t3.medium"
  name          = "web-server"
}

# Reference module output
output "server_id" {
  value = module.web_server.instance_id
}

Module Sources

# Local
source = "./modules/vpc"

# Public registry
source = "terraform-aws-modules/vpc/aws"

# Private registry
source = "app.terraform.io/org-name/vpc/aws"

// Knowledge Check

What allows reusing Terraform configurations?

Hint: ???

What attribute references module outputs?

Hint: module.???.output

Show Answers

Answers

  1. modules
  2. source

// Lesson 7: Workspaces

×

What Are Workspaces?

Workspaces let you manage multiple environments from the same configuration. Each workspace has its own state file.

Creating Workspaces

# List workspaces
terraform workspace list

# Create new workspace
terraform workspace new dev

# Switch workspace
terraform workspace select prod

# Delete workspace
terraform workspace delete staging

Using Workspaces in Code

# Use workspace in resource names
resource "aws_instance" "web" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = var.instance_type
  
  tags = {
    Name = "web-${terraform.workspace}"
  }
}

# Conditional based on workspace
resource "aws_instance" "prod_db" {
  count = terraform.workspace == "prod" ? 1 : 0
  # ...
}

Workspace Best Practices

# Each workspace should have separate state
# dev/terraform.tfstate
# prod/terraform.tfstate

# Use separate state backends
terraform {
  backend "s3" {
    bucket = "my-terraform-state"
    key    = "${terraform.workspace}/terraform.tfstate"
  }
}

// Knowledge Check

What separates state between environments?

Hint: terraform.???

What command creates a new workspace?

Hint: terraform workspace ???

Show Answers

Answers

  1. workspace
  2. new

// Lesson 8: Provisioners

×

Running Scripts After Creation

Provisioners let you execute scripts on local or remote machines after resource creation.

Local Provisioner

resource "aws_instance" "web" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t3.micro"
  
  provisioner "local-exec" {
    command = "echo ${self.private_ip} > inventory.txt"
  }
}

Remote Provisioner

resource "aws_instance" "web" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t3.micro"
  
  connection {
    type     = "ssh"
    user     = "ubuntu"
    private_key = file("~/.ssh/id_rsa")
    host     = self.public_ip
  }
  
  provisioner "remote-exec" {
    inline = [
      "sudo apt-get update",
      "sudo apt-get install -y nginx",
      "sudo systemctl enable nginx",
      "sudo systemctl start nginx"
    ]
  }
}

File Provisioner

provisioner "file" {
  content     = templatefile("nginx.conf.tpl", { domain = var.domain })
  destination = "/etc/nginx/sites-available/${var.domain}"
}

// Knowledge Check

What runs a script on the machine running Terraform?

Hint: ??? provisioner

What runs a script on the created resource?

Hint: ??? provisioner

Show Answers

Answers

  1. local-exec
  2. remote-exec

// Lesson 9: Terraform in CI/CD

×

Automating Terraform

Use CI/CD pipelines to automate Terraform runs with proper approvals and security.

GitHub Actions Workflow

name: Terraform

on:
  push:
    branches: [main]
  pull_request:

jobs:
  terraform:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        
      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v2
        with:
          cli_config_credentials_token: ${{ secrets.TF_API_TOKEN }}
          
      - name: Terraform Init
        run: terraform init
        
      - name: Terraform Plan
        run: terraform plan
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          
      - name: Terraform Apply
        if: github.ref == 'refs/heads/main'
        run: terraform apply -auto-approve
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

Protected Environments

# Require approval for production
- name: Terraform Apply
  if: github.ref == 'refs/heads/main' && needs.plan.outputs.approved == 'true'
  run: terraform apply -auto-approve

// Knowledge Check

What action sets up Terraform in GitHub Actions?

Hint: hashicorp/???

What flag auto-approves Terraform changes?

Hint: terraform apply ???

Show Answers

Answers

  1. setup-terraform
  2. -auto-approve

// Lesson 10: Testing & Validation

×

Terraform Validation

# Syntax validation
terraform validate

# Format check
terraform fmt -check

# Check for breaking changes
terraform plan -detailed-exitcode

Terratest

// Example Terratest in Go
package test

import (
    "testing"
    "github.com/gruntwork-io/terratest/modules/terraform"
)

func TestTerraformWebServer(t *testing.T) {
    terraformOptions := &terraform.Options{
        TerraformDir: "../examples/web-server",
        Vars: map[string]interface{}{
            "instance_type": "t3.micro",
        },
    }
    
    defer terraform.Destroy(t, terraformOptions)
    terraform.InitAndApply(t, terraformOptions)
    
    instanceID := terraform.Output(t, terraformOptions, "instance_id")
    t.Logf("Instance ID: %s", instanceID)
}

Sentinel (Enterprise)

# Sentinel policy example
import "tfrun"

# Prevent production deployments on Fridays
main = rule {
    tfrun.workspace.name != "prod" or
    time.now.weekday != "Friday"
}

// Knowledge Check

What command validates Terraform syntax?

Hint: terraform ???

What testing framework uses Go?

Hint: ???

Show Answers

Answers

  1. validate
  2. terratest

// Lesson 11: Multi-Cloud Patterns

×

Multi-Cloud with Terraform

Terraform's provider-agnostic approach lets you manage multiple clouds with the same tool.

Multiple Providers

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
    google = {
      source  = "hashicorp/google"
      version = "~> 4.0"
    }
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 3.0"
    }
  }
}

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

provider "google" {
  region = "us-central1"
}

provider "azurerm" {
  features {}
}

Abstracting Providers

# Use variables for cloud-agnostic configs
variable "cloud_provider" {
  type    = string
  default = "aws"
}

locals {
  vm_settings = var.cloud_provider == "aws" ? {
    ami = "ami-0c55b159cbfafe1f0"
  } : var.cloud_provider == "gcp" ? {
    source_image = "ubuntu-2204"
  } : {}
}

// Knowledge Check

What lets Terraform work with multiple clouds?

Hint: ???

What block creates cloud-agnostic configurations?

Hint: ??? block

Show Answers

Answers

  1. providers
  2. locals

// Lesson 12: Enterprise Patterns

×

Terragrunt

# terragrunt.hcl
terraform {
  source = "git::https://github.com/org/modules//web-app?ref=v1.0.0"
}

inputs = {
  instance_type = "t3.medium"
  desired_capacity = 3
}

dependency "vpc" {
  config_path = "../vpc"
}

Policy as Code

# OPA Rego policy
package terraform

deny[msg] {
  input.resource.aws_instance.type == "t2.micro"
  msg = "Use t3 instances instead of t2"
}

deny[msg] {
  input.resource.aws_s3_bucket.public_read
  msg = "S3 buckets must not be public"
}

Terraform Cloud/Enterprise

  • Remote State: Secure state storage
  • Policy Enforcement: Sentinel policies
  • Cost Estimation: Before apply
  • Private Registry: Share modules
  • Role-Based Access: Team permissions

// Knowledge Check

What tool wraps Terraform for better organization?

Hint: ???

What enforces policies in Terraform Enterprise?

Hint: ??? policies

Show Answers

Answers

  1. terragrunt
  2. sentinel

// Tools & References

📖 Terraform Docs

Official Terraform documentation

developer.hashicorp.com

☁️ AWS Provider

AWS resources in Terraform

registry.terraform.io

🧪 Terratest

Testing infrastructure code

terratest.gruntwork.io

📦 Terragrunt

Terraform wrapper for DRY

terragrunt.gruntwork.io

📜 Terraform Book

Infrastructure as Code book

oreilly.com

🔧 Terraform Cloud

Managed Terraform service

terraform.io/cloud