Infrastructure as Code: Terraform, State and Drift

Infrastructure as code explained: declarative vs imperative, Terraform plan and apply, remote state and locking, modules, drift detection and policy checks.

Intermediate 3 min read · Updated

Infrastructure as code (IaC) manages servers, networks, databases, permissions and other cloud resources through version-controlled definition files instead of manual clicks. A tool such as Terraform (or OpenTofu, Pulumi, CloudFormation) compares the code with what exists, shows a plan of changes, and applies them. The result is infrastructure that's reviewable, repeatable across environments, and recoverable.

Declarative vs imperative

DeclarativeImperative
You writeThe desired end state: "there is a bucket with versioning on"Steps: "create a bucket, then enable versioning"
RerunningSafe: the tool computes what's differentMay fail or duplicate if steps already ran
ExamplesTerraform, CloudFormation, Kubernetes manifestsShell scripts, some configuration tools

Declarative tools are idempotent by design, which is what makes repeated applies, drift correction and new environments safe.

Plan, apply and state

Pull request*.tf changesPlan in CIdiff vs statePolicy checksOPA · cost · securityHuman reviewApplyafter mergeRemote statelocked · versionedCloud APIs
A change flows through review: the plan is computed against real state, reviewed and checked by policy, then applied by CI with a locked state file.
  • State maps each resource in code to the real object it manages (its cloud ID and attributes). Without it, the tool can't tell what it created.
  • Remote state with locking: store state in shared, versioned storage and lock it during applies so two people can't change the same infrastructure concurrently and corrupt it.
  • State is sensitive: it can contain secrets and resource details, so encrypt it and restrict access.
  • Apply only reviewed plans: CI should apply the exact plan that was reviewed, not recompute a different one later.

Modules and structure

  • Modules package a reusable pattern (a service's database with backups, alarms and access policies) with a small set of inputs, so teams don't copy hundreds of lines.
  • Version modules and upgrade consumers deliberately, like library dependencies.
  • Split state by blast radius: one giant state file means every plan touches everything and one mistake can affect production broadly. Separate by environment, region and component (network, data, services).
  • Same code, different variables per environment, so staging is a faithful rehearsal of production.

Drift

Drift is when reality no longer matches the code, usually because someone changed a resource by hand during an incident. The next apply might silently revert the fix or fail. Detect drift by running scheduled plans and alerting on unexpected differences; resolve it by updating the code to match (if the change was right) or re-applying (if it wasn't). Reduce it by limiting write access in the console to break-glass roles.

Guardrails

  • Policy as code: automated checks on plans, for example no public buckets, encryption required, approved instance types, tags for cost ownership.
  • Destructive change protection: flag plans that delete or replace stateful resources such as databases, and require extra approval.
  • Least-privilege CI credentials: the pipeline that applies changes uses short-lived credentials scoped to what it manages. See secrets management.
  • Import before managing: bring existing resources under IaC by importing them into state, not by recreating them.

IaC is how you get disaster recovery for infrastructure: if a region or account is lost, the same code can rebuild it, as long as it's been exercised recently.

Where it’s used

Platform teams

Versioned modules for networks, clusters and databases let product teams self-serve standard infrastructure.

Multi-environment delivery

The same code with different variables builds identical dev, staging and production stacks.

Compliance

Every infrastructure change has a reviewed pull request and policy checks, giving an audit trail.

In an interview

  • Explain plan, apply and why remote state needs locking.
  • Split state by environment and component to limit blast radius.
  • Detect and resolve drift with scheduled plans.
  • Add policy checks and protection for destructive changes.

Further reading