DevOps Infrastructure as Code with Terraform
Infrastructure as Code (IaC) means managing and provisioning IT infrastructure — servers, databases, networks, load balancers — through code files instead of manual steps in a web console. The infrastructure is defined in text files, stored in Git, reviewed like application code, and applied automatically.
Terraform, built by HashiCorp, is the most widely used IaC tool. It works with virtually every cloud provider: AWS, Azure, Google Cloud, and many others.
Why Infrastructure as Code?
Consider setting up a production environment manually through the AWS console. This involves clicking through dozens of screens, remembering configurations, and hoping nothing was missed. Now imagine doing this again for staging and development environments — and doing it consistently every time.
IaC solves this with several key benefits:
- Repeatability: Run the same code and get the exact same infrastructure every time.
- Version Control: Infrastructure changes go through Git — with history, review, and rollback.
- Consistency: Dev, staging, and production environments are identical.
- Speed: Provision complete cloud environments in minutes instead of hours.
- Documentation: The code is the documentation. No need for separate runbooks.
- Cost Control: Destroy environments when not in use with a single command.
How Terraform Works
Terraform uses a declarative approach: describe what infrastructure is needed and Terraform figures out how to create it. The configuration is written in HCL (HashiCorp Configuration Language) — a simple, human-readable format.
The Three Core Commands
# Preview what changes Terraform will make
terraform plan
# Apply the changes and create/modify infrastructure
terraform apply
# Destroy all managed infrastructure
terraform destroyTerraform Core Concepts
Provider
A provider is a plugin that tells Terraform how to talk to a specific cloud or service. Each provider offers a set of resources that can be managed.
Resource
A resource represents a single piece of infrastructure — an EC2 instance, an S3 bucket, a database. Resources are the main building blocks of Terraform code.
State File
Terraform maintains a state file (terraform.tfstate) that records the current state of managed infrastructure. This allows Terraform to calculate what changes are needed on the next apply. In teams, the state file is stored remotely (S3, Azure Blob, Terraform Cloud) so everyone shares the same source of truth.
Module
A module is a reusable group of Terraform resources. Instead of writing the same code for every environment, create a module once and call it with different parameters for dev, staging, and production.
Variables and Outputs
Variables make configurations flexible and reusable. Outputs expose values (like an IP address or URL) after infrastructure is created.
Terraform Project Structure
my-infrastructure/
├── main.tf # Main resource definitions
├── variables.tf # Input variable declarations
├── outputs.tf # Output value definitions
├── providers.tf # Provider configuration
└── terraform.tfvars # Variable values (not committed to Git)Complete Example – AWS EC2 Instance with Security Group
providers.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = var.aws_region
}variables.tf
variable "aws_region" {
description = "AWS region to deploy resources"
type = string
default = "us-east-1"
}
variable "instance_type" {
description = "EC2 instance type"
type = string
default = "t3.micro"
}
variable "app_name" {
description = "Application name tag"
type = string
}main.tf
# Security group to allow HTTP and SSH
resource "aws_security_group" "web_sg" {
name = "${var.app_name}-sg"
description = "Allow HTTP and SSH traffic"
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["10.0.0.0/8"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
# EC2 instance
resource "aws_instance" "web_server" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = var.instance_type
vpc_security_group_ids = [aws_security_group.web_sg.id]
tags = {
Name = "${var.app_name}-server"
Environment = "production"
}
}outputs.tf
output "server_public_ip" {
description = "Public IP of the web server"
value = aws_instance.web_server.public_ip
}
output "server_id" {
description = "EC2 Instance ID"
value = aws_instance.web_server.id
}Terraform Workflow Step by Step
- Initialize: Download provider plugins and set up the working directory.
terraform init - Validate: Check the configuration for syntax errors.
terraform validate - Plan: Preview all changes before applying them.
terraform plan -var="app_name=mywebapp" - Apply: Create or update the infrastructure.
terraform apply -var="app_name=mywebapp" - Destroy: Remove all managed infrastructure when no longer needed.
terraform destroy
Remote State – Team Collaboration
When a team uses Terraform together, the state file must be shared. Storing it locally causes conflicts. The standard approach is remote state on S3 with DynamoDB for locking:
terraform {
backend "s3" {
bucket = "mycompany-terraform-state"
key = "production/webapp/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-state-lock"
encrypt = true
}
}DynamoDB prevents two engineers from running apply simultaneously, which could corrupt the state.
Terraform Modules
Modules are reusable packages of Terraform code. The community publishes modules on the Terraform Registry for common patterns:
# Use a community VPC module from the registry
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "5.0.0"
name = "production-vpc"
cidr = "10.0.0.0/16"
azs = ["us-east-1a", "us-east-1b"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24"]
}Terraform in a DevOps Pipeline
Infrastructure changes go through the same CI/CD pipeline as application code:
- Engineer makes a change to a
.tffile and opens a pull request. - CI pipeline runs
terraform planand posts the output as a comment on the PR. - Team reviews the planned changes before approving the PR.
- After merge, the CD pipeline runs
terraform applyautomatically. - Infrastructure changes are applied, tracked in Git, and auditable.
Summary
- Infrastructure as Code replaces manual console clicks with version-controlled configuration files.
- Terraform uses HCL to define cloud resources in a declarative, human-readable format.
- The core workflow is: init → validate → plan → apply.
- State files track real-world infrastructure — store them remotely for team collaboration.
- Modules enable reuse and consistency across multiple environments.
- Integrating Terraform into CI/CD pipelines makes infrastructure changes as reviewable and auditable as application code.
