Infrastructure as Code#
Infrastructure-as-Code (IaC) treats infrastructure the same way as application code: defined in version-controlled files, reviewed in pull requests, and applied by automation rather than clicked into a console.
flowchart LR
Dev[Engineer] -->|edit + PR| Git[(Git Repo)]
Git -->|plan in CI| CI[CI Pipeline]
CI -->|terraform plan| Plan[Plan Artifact]
Plan -->|review| Reviewer
Reviewer -->|approve + merge| Git
Git -->|apply| Apply[terraform apply]
Apply -->|update| State[(Remote State<br/>+ Lock)]
Apply -->|provision| Cloud[Cloud APIs]
Cloud --> Resources[VPCs / VMs / Buckets / IAM]
Resources -.->|drift detection| Plan
Provisioning Tools#
The IaC tools an operator picks among. Terraform leads on broad cloud coverage with HCL; OpenTofu is the open-source fork; Pulumi authors infrastructure in real programming languages; CloudFormation, CDK, Bicep are cloud-specific; Crossplane brings provisioning into Kubernetes itself.
Terraform , HCL, broad provider ecosystem, state-based.
OpenTofu , open-source Terraform fork.
Pulumi , author in TypeScript / Python / Go / C#.
AWS CloudFormation, YAML/JSON, AWS-native.
AWS CDK , author CloudFormation in code.
Bicep, Azure-native.
Crossplane , Kubernetes-native cloud provisioning.
A Tiny Terraform Example#
terraform {
required_providers {
aws = { source = "hashicorp/aws", version = "~> 5.0" }
}
}
provider "aws" {
region = "us-east-1"
}
resource "aws_s3_bucket" "logs" {
bucket = "myorg-logs-${var.env}"
}
variable "env" {
type = string
default = "dev"
}
output "bucket_name" {
value = aws_s3_bucket.logs.id
}
$ terraform init
$ terraform fmt
$ terraform validate
$ terraform plan -out tfplan
$ terraform apply tfplan
$ terraform destroy
State#
Terraform records what it created in a state file. Treat state with care:
Store remotely (S3 + DynamoDB lock, Terraform Cloud, GCS, Azure storage).
Lock during applies to prevent concurrent runs.
Never edit by hand in production.
Use
terraform importto bring existing resources under management.
Configuration Management#
The other half of IaC, describing what runs on a server, not just which servers exist. Ansible’s agentless YAML playbooks dominate today; Chef, Puppet, and Salt cover the mature alternatives. Increasingly, configuration moves into container images, leaving CM for traditional VM fleets.
For per-server configuration (packages, files, services), the classic tools are:
Ansible, agentless, YAML playbooks over SSH.
Chef, Ruby DSL, agent-based.
Puppet , declarative DSL, agent-based.
Salt , ZeroMQ pub-sub, fast at fleet scale.
A minimal Ansible playbook:
- hosts: web
become: true
tasks:
- name: install nginx
apt: { name: nginx, state: latest, update_cache: true }
- name: ensure nginx is running
service: { name: nginx, state: started, enabled: true }
Patterns#
The patterns that turn IaC from a folder of files into a production discipline. Modules for reuse, separate state per environment, plan-in-CI / apply-on-merge for review, periodic drift detection, and consistent resource tagging all show up in mature setups.
Modules / charts, bundle a reusable piece of infrastructure with inputs and outputs.
Environments via workspaces or directories, separate state per env (dev/staging/prod).
Plan in CI, apply on merge, review changes before they land.
Drift detection, run
terraform planperiodically; alert on unexpected diffs.Tagging strategy, consistent tags (
env,owner,cost-center) on every resource.