Terraform and OpenTofu: Cloud Infrastructure as Code

Terraform and OpenTofu are open-source declarative Infrastructure as Code (IaC) engines that enable provisioning, updating, and managing cloud resources (AWS, Azure, GCP, Kubernetes) using HashiCorp Configuration Language (HCL2).


⚡ Quick Dive

CLI Command Cheat Sheet

Command Action Example
tofu init / terraform init Initialize working directory & download provider plugins tofu init -upgrade
tofu plan Generate and preview execution plan against remote API tofu plan -out=tfplan
tofu apply Apply changes to reach desired state tofu apply tfplan
tofu destroy Tear down and destroy all tracked infrastructure tofu destroy -target=module.staging
tofu fmt Rewrites config files to canonical formatting tofu fmt -recursive
tofu validate Verifies configuration syntax and internal consistency tofu validate
tofu state list List all managed resources inside the state file tofu state list
tofu output Extract value of output variables from state tofu output -raw cluster_endpoint

Production Project Structure

infrastructure/
├── main.tf           # Root module resources and provider bindings
├── variables.tf      # Input variable type definitions & defaults
├── outputs.tf        # Output values exported from the state
├── terraform.tf      # Required providers and remote backend configuration
├── terraform.tfvars  # Environment-specific variable assignments
└── modules/          # Reusable local modules
    ├── vpc/
    └── eks/

📖 Extended Guide

1. Remote State & Distributed State Locking

In team environments, never store terraform.tfstate on local developer machines. Use a remote backend with distributed state locking to prevent race conditions during concurrent runs.

AWS S3 + DynamoDB Remote Backend Configuration (terraform.tf):

terraform {
  required_version = ">= 1.8.0"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.50"
    }
  }

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

2. Core HCL2 Blocks & Idioms

# variables.tf
variable "environment" {
  type        = string
  description = "Target deployment environment"
  default     = "production"
}

variable "vpc_cidr" {
  type        = string
  description = "CIDR block for VPC"
  validation {
    condition     = can(cidrnetmask(var.vpc_cidr))
    error_message = "Must be a valid IPv4 CIDR block."
  }
}

# main.tf
locals {
  common_tags = {
    Environment = var.environment
    ManagedBy   = "Terraform"
  }
}

# Data source: query existing cloud metadata
data "aws_availability_zones" "available" {
  state = "available"
}

# Resource definition
resource "aws_vpc" "main" {
  cidr_block           = var.vpc_cidr
  enable_dns_hostnames = true
  enable_dns_support   = true

  tags = merge(local.common_tags, {
    Name = "${var.environment}-vpc"
  })

  lifecycle {
    # Prevent accidental destruction of critical infrastructure
    prevent_destroy = true
  }
}

# outputs.tf
output "vpc_id" {
  value       = aws_vpc.main.id
  description = "ID of the provisioned VPC"
}

3. Resource Lifecycle Customization

HCL lifecycle blocks control how Terraform manages resource replacement:

  • create_before_destroy = true: Creates the replacement resource before terminating the old one (essential for zero-downtime DNS, load balancers, and certificates).
  • prevent_destroy = true: Rejects any terraform destroy or plan that would delete this critical resource (databases, main VPCs).
  • ignore_changes = [ tags["UpdatedBy"] ]: Prevents Terraform from reverting changes made by external autoscalers or security tools.