Declarative Infrastructure
Infrastructure as Code (IaC) is the practice of defining infrastructure (VMs, networks, databases, DNS) in versioned, reviewable files instead of clicking in a cloud console. The Terraform model is declarative: you describe the desired state — “one VPC, two subnets, one database, four web servers” — and Terraform figures out the diff between reality and your declaration, then applies only what changed.
terraform apply: 9 to add, 2 to change, 0 to destroy
That diff is the entire point: infrastructure changes become reviewable pull requests, reproducible from scratch, and recoverable — the same declaration that built staging builds production.
The Core Objects
- Providers — plugins that speak each platform’s API (AWS, GCP, Azure, Kubernetes, GitHub, Cloudflare). The provider translates Terraform’s resource model into real API calls.
- Resources — the units of infrastructure:
aws_instance,google_storage_bucket,kubernetes_deployment. Each has a type, a name, and config attributes; Terraform tracks dependencies between them. - Data sources — read existing infrastructure without managing it: “look up the current AMI,” “find an existing VPC” — so you can reference things not owned by this config.
- Variables and outputs — parameterize configs (
var.environment) and expose created values (output "db_endpoint"). - Modules — reusable, parameterized packages of resources. The golden rule: don’t repeat resource blocks — wrap the “standard web service” (load balancer + instances + security group) in a module and instantiate it per environment.
The Workflow
terraform init— downloads providers and sets up the backend.terraform plan— computes the diff and shows it to you; this is the reviewable artifact.terraform apply— executes the plan.terraform destroy— tears down everything the config created.
The plan/apply split is what makes IaC reviewable: CI shows the plan on every PR, a human approves, and only then does infrastructure change.
State: Terraform’s Memory
Terraform keeps a state file — a JSON map of every managed resource and its real attributes. It’s how the next plan knows what it already created. Treat state with the respect it deserves:
- Never edit by hand (unless you know the surgical commands for it).
- Lock it — concurrent applies corrupt state; remote backends (S3+DynamoDB lock, Terraform Cloud, GCS) provide locking.
- Keep it remote — a local
terraform.tfstateon a laptop is a single point of loss. The backend stores state centrally; teams share it; CI reads/writes it.
State contains secrets (resource attributes like passwords that were interpolated) — so it lives in a private, encrypted bucket, with access controlled, not in your repo.
Dependency Graph
Terraform builds a dependency graph from your resources and applies in dependency order: the security group before the instance that references it, the VPC before its subnets. terraform graph prints it; -target applies a subset; taint/replace force specific recreations. You rarely fight the ordering — you just need to reference resources (aws_instance.web.id) and let the graph do the rest.
Code Review Culture and Testing
- Formatting/lint —
terraform fmt,terraform validate, plus linters liketfsec/checkovfor misconfigurations (public S3 buckets, open security groups). - Static analysis in CI — plan in a PR, fail on security findings.
terraform plan -destroyin staging validates teardown before production ever gets the same declaration.
The security angle (from the Security track) lands here: a resource declared public is public forever — IaC makes misconfigurations auditable and preventable at the plan step, which is why “public S3 bucket” findings almost always trace back to a config someone reviewed.
Practice Trajectory
- Declare a tiny resource set (a bucket or an instance) locally with
terraform init/plan/apply/destroy; read every line of the plan. - Reference a resource’s output from another resource and confirm the dependency graph orders them.
- Move state to a remote backend with locking and run two concurrent applies to watch the lock.
- Extract a “web service” module and instantiate it for
devandprodwith different variables. - Run
tfsec(or checkov) against your config and fix every security finding it reports.
When It’s the Right Tool
| Situation | Takeaway |
|---|---|
| Cloud resources that must be reproducible | Terraform |
| Infra changes need review/audit | Plan + PR + apply pipeline |
| Same infra across environments | Modules + variables |
| Team coordination on shared infra | Remote state + locking |
| One-off test environment | Terraform is still right — destroy after use |