Skip to main content
RunBook Academy

TerraformI · Infrastructure as Code FoundationsFoundations

Why Infrastructure as Code Exists

Foundation⏱ ~14 minbash

What you'll learn

  • Explain the operational pain of manual infrastructure, audit gaps, drift, and slow change
  • Compare the four provisioning approaches (manual, scripts, configuration management, IaC) by failure surface
  • Identify the table-stakes properties that distinguish IaC from script-based provisioning
  • List the production defaults that follow from disciplined IaC adoption
  • Recognise when IaC is the right choice and when it is not

Prerequisites

None — start here.

Verified against Terraform CLI 1.9.x · OpenTofu 1.7.x · HCL 2.0 · bpg/proxmox provider 0.66+ · hashicorp/local provider 2.5+ · hashicorp/null provider 3.2+ · hashicorp/random provider 3.6+ · hashicorp/http provider 3.4+ · Ubuntu 24.04 LTS · Debian 12 (Bookworm) · 2026-08-13

Not yet marked complete on this device.

Before Infrastructure as Code existed at scale, infrastructure was a memory problem. The two engineers who knew why the disks were laid out the way they were had stopped writing runbooks. The firewall rules on the staging database were “what Carlos did in 2022”. The on-call rotation included a person whose only qualification was having been there long enough to remember where the secrets lived.

That is not a caricature. That is the default state of a manual infrastructure team after eighteen months. IaC is the discipline that replaces memory with files.

The operational pain that motivated IaC

Four classes of problem recur in manual infrastructure. They are the reason IaC exists at all.

Snowflake servers. Every machine is slightly different, for reasons no one writes down. After a year, the team has forty db-prod servers and no two are identical. One of them runs a kernel patch the rest do not. Re-creating one means re-discovering the configuration from scratch.

Audit gaps. “Why is the security group open on port 22 to 0.0.0.0/0?” The audit answer is a Slack thread from a year ago. The compliance answer is “we’ll need to investigate”. Neither helps when the auditor wants a commit hash.

Drift. The real world diverges from intent. A junior engineer fixes a stuck deploy by editing a security group in the console. Nothing records the change. Six months later, the team believes the rule is locked down. It is not.

Slow change. Standing up a new environment takes three weeks because it is a manual exercise that nobody has done recently. The team re-learns the cloud console every time. The cost of a new environment is not the AWS bill; it is the calendar.

These four are not independent. Drift creates snowflake servers. Snowflake servers make audits painful. Slow change makes every fix a hand-rolled special case. IaC attacks all four at once.

The four provisioning approaches

Each step down removes a category of failure. Each step introduces a new tool with new failure modes to learn.

Manual (portal clicks)
   ↓
Shell and API scripts
   ↓
Configuration management (Ansible, Puppet, Chef)
   ↓
Infrastructure as Code (Terraform, OpenTofu)

Manual. A human runs the cloud console. The result is a server that one engineer could probably recreate from memory and no one else could. There is no audit trail beyond “Ed saw it happen” and no way to ask “what would change if I ran this again?”

Shell and API scripts. The same manual steps captured in a bash script and checked into Git. Faster to run than manual, and now reviewable. But the script describes steps, not state. If it fails at step 7, the environment is in an undefined half-state and re-running from the start is unsafe.

Configuration management. Tools like Ansible, Puppet, and Chef add idempotency. The script describes a desired state; the tool inspects reality and applies only the differences. They are excellent at managing software on hosts that already exist. They do not, on their own, create the hosts.

Infrastructure as Code. A descriptive file declares what should exist. A tool reads the file, compares it to the real world (via a state file), and applies the differences. The state file is what makes subsequent operations safe. The file is what makes the configuration reviewable.

The other lessons in this part cover each of these boundaries in detail. The remainder of this lesson focuses on what IaC delivers, period, and what it costs.

Why IaC won

IaC is not the only IaC tool. It won the category, not the implementation. Five properties distinguish IaC from script-based provisioning, and they are the reason teams standardise on it.

Property           | Manual | Scripts | CM   | IaC
--------------------+--------+---------+------+-----
Reviewable         |   no   |   yes   |  yes | yes
Versioned          |   no   |   yes   |  yes | yes
Idempotent          |   no   |   no    |  yes | yes
Plan-able           |   no   |   no    |  no  | yes
Drift-aware        |   no   |   no    | weak | yes

The two columns on the right — plan-able and drift-aware — are the ones that drove IaC adoption. Everything in IaC flows from the fact that the tool can answer a question script-based tools cannot: what would change if I ran this now?

  • Plan-able. terraform plan produces a precise diff between declared intent and the real world, before any change is made. A script cannot answer that question because it does not know what is there.
  • Drift-aware. The state file is a record of the last known real-world condition. A subsequent plan against unchanged configuration reveals drift. Scripts cannot see drift.

Without plan-ability, every change is a leap of faith. Without drift detection, the declaration is a story the team tells itself that diverges from the truth.

Production defaults that follow

If you do IaC well, several operational habits become the default, not the policy. They fall out of the model.

Reviewable changes. Every state change ships through a pull request. The diff is the change. The CI run shows the plan. The reviewer signs off on intent, not on hope.

Immutable posture. Replace, do not mutate. Patch a server by replacing it, not by ssh-ing in and editing a config file. The new thing is described in a file before it exists.

State as a record. The state file records what Terraform believes exists. The configuration is the source of truth for what should exist. When they disagree, the production default is to investigate — not to assume the configuration is correct.

Blast-radius awareness. A change touches a known set of resources. The reviewer can see the set from the plan. The apply is gated on the size of the set.

Plan-first culture. “Did you run terraform plan?” is a rhetorical question in a healthy team. The plan is the change proposal. Without it, the change is not proposed.

These five are not aspirational. They are what disciplined IaC looks like on day one. Teams that skip them are still running scripts, even if the file extension is .tf.

When IaC is NOT the right choice

IaC has a real cost. It is not free, and not every workload earns it.

  • A single throwaway VM for a one-day investigation. The setup cost exceeds the value.
  • Highly dynamic, ephemeral workloads. Containers scheduled thousands of times per hour are the wrong scale model. The right tool is a scheduler, not a provisioner.
  • Configuration that the provider does not expose. Some legacy APIs cannot be expressed as IaC. A script calling a SOAP endpoint is not a Terraform problem to solve.
  • Workloads where the real world is the source of truth. A manually maintained AD forest, for example, where every change is human judgement.

The rule of thumb: if the work can be re-derived from a file, IaC is the right tool. If the work is irreducibly interactive, IaC adds friction without removing it.

How to validate IaC is actually being adopted

The test is whether the team uses the tool as the source of truth, not as a notation. Three checks:

# READ-ONLY: how many production changes bypass Terraform this week?
git -C infra/search? log --since='1 week ago' --grep='manual'
# READ-ONLY: what is in the state? is it growing or shrinking?
terraform state list | wc -l
# READ-ONLY: does the plan reflect reality?
terraform plan -detailed-exitcode
# exit code: 0 = no changes, 1 = error, 2 = changes pending

If the answers are “we don’t know”, “growing but not sure why”, and “two”, the team has IaC files but not IaC discipline. The files are documentation. The discipline is the operational practice.

Production failure modes for IaC adoption

Five recurrent patterns kill IaC rollouts before they reach the team they are supposed to help.

  1. Pilot without mandate. A single team pilots IaC while the rest of the organisation continues to click in the console. The console changes cause drift. The pilot team is asked to fight the drift without authority.
  2. State in the wrong place. The state file lives on one engineer’s laptop. When they are on holiday, no one can apply.
  3. No plan-review gate. PRs that change .tf files merge without a plan posted in the conversation. The first reviewer learns what the change does from the apply log.
  4. Configuration sprawl. Dozens of root modules in a single directory, no module boundaries, no testing. The IaC repo becomes the snowflake it was meant to replace.
  5. Owned by no one. The IaC repo is “everyone’s”, which means it is no one’s. Merges happen at 17:00 on Fridays with no reviewer familiar with the area. The later lessons in this part cover ownership directly.

Security implications

IaC repos contain the map of the production estate. Treat them as production credentials.

  • Read access to the IaC repo reveals security group rules, IAM policies, subnet ranges, and the topology. Lock down read access to “need to know” for production topology.
  • Write access to the IaC repo is the ability to change production. Lock it with CODEOWNERS, signed commits, and CI-enforced plan gates.
  • State backends hold the same information as the files, plus the resource IDs and current attribute values. Encrypt them at rest. Restrict access by role.

The course has a dedicated security chapter. For this lesson: the IaC repo and state backend are the new privileged perimeter.

Performance implications

Terraform’s plan-time cost is CPU-bound on the resource graph construction. For estates of a few hundred resources, the cost is negligible. For estates of tens of thousands, the plan can take minutes.

Two mitigations:

  • Split the configuration. Smaller root modules with explicit module boundaries plan faster.
  • Parallelise via remote execution. Terraform Cloud and Atlantis distribute the plan across workers.

The course covers module boundaries and CI/CD later. For this lesson: if the plan is slow, the configuration is too coarse.

What comes next

The next lesson covers the declarative versus imperative boundary — what Terraform is, what it is not, and why treating a declarative tool as a procedural one is the most expensive confusion in the IaC world.

Verification

The lesson teaches a principle; the verification asks whether the principle is in operation. Four checks, all read-only.

# READ-ONLY: are changes reaching the repo as PRs?
# Look for the absence of `apply` against local state files
# in the production environment, and the presence of
# branch-protection rules requiring reviews.
gh api repos/{owner}/{repo}/rules/branches/main \
  | jq '.required_pull_request_reviews.required_approving_review_count'

# READ-ONLY: is there a plan posted in every IaC PR?
# A PR template that includes a `### Plan` heading is the
# usual mechanism.
gh api repos/{owner}/{repo}/contents/.github/PULL_REQUEST_TEMPLATE.md \
  --jq '.content' | base64 -d | grep -c 'Plan'

# READ-ONLY: is drift detection scheduled?
# Terraform Cloud workspaces expose drift-detection schedules;
# self-hosted setups often use a cron job or CI schedule.
gh api /repos/{owner}/{repo}/environments \
  | jq '.environments[] | select(.name | test("plan"))'

# READ-ONLY: is CODEOWNERS in place?
test -f .github/CODEOWNERS && echo "yes" || echo "no"

A team that passes all four has IaC in operation. A team that fails one has IaC in files. The lesson is about the former, not the latter.

Knowledge check · 7 questions

  1. Q1. Which production pain motivated the move from manual infrastructure to IaC?

  2. Q2. Which property is unique to IaC compared with shell scripts?

  3. Q3. Manual infrastructure is reproducible across a team of three.

  4. Q4. Which of the following are production defaults that follow from disciplined IaC adoption? (Select all that apply.)

  5. Q5. A team of twelve has twelve different methods for standing up the same service. What is the first IaC priority?

  6. Q6. A production incident requires urgent change to a security group. The IaC-first answer is:

  7. Q7. The IaC repo is well-formatted, has CI, and the state is in Terraform Cloud. But the team still fixes production issues via the console. What is missing?

Passing score: 75%. Answers are checked in this browser.