DeveloperBootstrap

DevOps

Terraform Infrastructure as Code Complete Guide

Master Terraform for infrastructure as code with AWS, GCP, Azure, state management, modules, workspaces, and production best practices.

What you'll learn

  • Install Terraform and configure cloud provider credentials
  • Write HCL resources, variables, and outputs
  • Manage remote state with S3 and DynamoDB locking
  • Structure reusable modules
  • Use workspaces for multi-environment deployments
  • Plan, apply, and safely destroy infrastructure
  • Integrate Terraform into CI/CD with GitHub Actions

Installation & Setup

Bash
1# Install Terraform on Ubuntu 24.04
2wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor \
3  -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
4echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] \
5  https://apt.releases.hashicorp.com $(lsb_release -cs) main" | \
6  sudo tee /etc/apt/sources.list.d/hashicorp.list
7sudo apt update && sudo apt install -y terraform
8
9terraform version
10
11# Configure AWS credentials
12aws configure
13# Or use environment variables:
14export AWS_ACCESS_KEY_ID=...
15export AWS_SECRET_ACCESS_KEY=...
16export AWS_DEFAULT_REGION=us-east-1

HCL Basics

HCL
1# main.tf
2terraform {
3  required_version = ">= 1.6"
4  required_providers {
5    aws = {
6      source  = "hashicorp/aws"
7      version = "~> 5.0"
8    }
9  }
10}
11
12provider "aws" {
13  region = var.aws_region
14}
15
16resource "aws_vpc" "main" {
17  cidr_block           = var.vpc_cidr
18  enable_dns_hostnames = true
19  tags = merge(local.common_tags, { Name = "${var.project}-vpc" })
20}
21
22resource "aws_instance" "web" {
23  ami           = data.aws_ami.ubuntu.id
24  instance_type = var.instance_type
25  subnet_id     = aws_subnet.public.id
26  tags          = { Name = "${var.project}-web" }
27}
28
29# variables.tf
30variable "aws_region"    { default = "us-east-1" }
31variable "project"       { type = string }
32variable "vpc_cidr"      { default = "10.0.0.0/16" }
33variable "instance_type" { default = "t3.micro" }
34
35# outputs.tf
36output "web_public_ip" { value = aws_instance.web.public_ip }
37
38# locals.tf
39locals {
40  common_tags = {
41    Project   = var.project
42    ManagedBy = "terraform"
43  }
44}

Remote State

HCL
1# backend.tf — S3 with DynamoDB locking
2terraform {
3  backend "s3" {
4    bucket         = "mycompany-terraform-state"
5    key            = "production/terraform.tfstate"
6    region         = "us-east-1"
7    encrypt        = true
8    dynamodb_table = "terraform-state-lock"
9  }
10}
11
12# Create the S3 bucket and DynamoDB table once manually (bootstrap module)
13# Then run:
14terraform init   # migrates state to backend
15terraform plan
16terraform apply

Modules

HCL
1# modules/vpc/main.tf — reusable VPC module
2variable "cidr"    {}
3variable "project" {}
4
5resource "aws_vpc" "this" {
6  cidr_block = var.cidr
7  tags       = { Name = "${var.project}-vpc" }
8}
9
10output "vpc_id"   { value = aws_vpc.this.id }
11output "vpc_cidr" { value = aws_vpc.this.cidr_block }
12
13# Root module usage
14module "vpc" {
15  source  = "./modules/vpc"
16  cidr    = "10.0.0.0/16"
17  project = var.project
18}
19
20# Or use the Terraform Registry
21module "vpc" {
22  source  = "terraform-aws-modules/vpc/aws"
23  version = "~> 5.0"
24  name    = var.project
25  cidr    = "10.0.0.0/16"
26  azs     = ["us-east-1a", "us-east-1b", "us-east-1c"]
27}

Workspaces

Bash
1terraform workspace new staging
2terraform workspace new production
3terraform workspace list
4terraform workspace select staging
5
6# Reference workspace in configuration
7resource "aws_instance" "web" {
8  instance_type = terraform.workspace == "production" ? "t3.medium" : "t3.micro"
9}
10
11# Better pattern: separate tfvars per environment
12terraform apply -var-file=environments/staging.tfvars
13terraform apply -var-file=environments/production.tfvars

CI/CD Integration

YAML
1# GitHub Actions — plan on PR, apply on merge to main
2jobs:
3  terraform:
4    runs-on: ubuntu-24.04
5    steps:
6      - uses: actions/checkout@v4
7      - uses: hashicorp/setup-terraform@v3
8        with:
9          terraform_version: "~1.6"
10
11      - run: terraform init
12        env:
13          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
14          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
15
16      - run: terraform validate
17      - run: terraform plan -out=tfplan
18
19      - name: Apply (main branch only)
20        if: github.ref == 'refs/heads/main'
21        run: terraform apply tfplan