# Infrastructure as Code Fundamentals

## 1. The Problem: ClickOps

Creating infrastructure by clicking through a cloud console works once. Then:

- Nobody remembers exactly which settings were chosen ("why is this security group open to 0.0.0.0/0?").
- Staging and production drift apart, so bugs appear only in production.
- Rebuilding after a disaster (or in a new region) takes days of guesswork.
- Changes have no review, no history, no rollback.

**Infrastructure as Code (IaC)** describes infrastructure in versioned text files that a tool turns into real resources. The same review, history, testing and automation you use for application code now applies to networks, databases, DNS, IAM and clusters.

## 2. Declarative vs Imperative

| | Imperative (scripts) | Declarative (desired state) |
|---|---|---|
| you write | the **steps**: "create VPC, then subnet, then…" | the **end state**: "there is a VPC with these 3 subnets" |
| re-running | may fail or duplicate ("VPC already exists") | idempotent: no changes if reality matches |
| changes | you script the transition | the tool computes the diff (plan) |
| examples | bash + AWS CLI, Ansible playbooks (mostly), SDK scripts | Terraform/OpenTofu, CloudFormation, Pulumi*, Kubernetes manifests |

\* Pulumi and AWS CDK use general-purpose languages but still produce a **declarative** model that an engine reconciles.

```hcl
# Declarative: "this bucket exists with versioning on"
resource "aws_s3_bucket" "assets" {
  bucket = "acme-prod-assets"
}
resource "aws_s3_bucket_versioning" "assets" {
  bucket = aws_s3_bucket.assets.id
  versioning_configuration { status = "Enabled" }
}
```

## 3. The IaC Tool Landscape

| Tool | Scope | Language | State |
|---|---|---|---|
| **Terraform / OpenTofu** | any cloud/SaaS with a provider (AWS, GCP, Azure, Cloudflare, GitHub, Datadog…) | HCL | state file you manage (remote backend) |
| **AWS CloudFormation** | AWS only | YAML/JSON | managed by AWS (stacks) |
| **AWS CDK** | AWS (synthesizes CloudFormation) | TS, Python, Java, C#, Go | CloudFormation stacks |
| **Pulumi** | multi-cloud | TS, Python, Go, C#, Java | Pulumi service or self-managed backend |
| **Ansible / Chef / Puppet** | configuring servers (packages, files, services) | YAML / Ruby DSL | mostly stateless |
| **Kubernetes manifests + Helm/Kustomize** | resources inside a cluster | YAML | the cluster itself (`devops-cloud/kubernetes/`) |

Rule of thumb: **provisioning** (create cloud resources) → Terraform/CloudFormation/CDK/Pulumi; **configuration** of long-lived servers → Ansible (increasingly replaced by immutable images + containers).

## 4. Core Principles

1. **Everything in version control** — infrastructure changes go through pull requests with review.
2. **Plan before apply** — always look at the computed diff; destructive changes must be visible.
3. **Idempotency** — running the same code twice changes nothing the second time.
4. **Immutable infrastructure** — replace servers/images instead of patching them in place; snowflake servers disappear.
5. **Environments from the same code** — dev/staging/prod differ only in variables (`06-workspaces_and_environments/`).
6. **No manual changes in production** — manual edits create **drift** between code and reality; detect and reconcile it (`07-terraform_in_ci_cd/`).
7. **Small blast radius** — split infrastructure into independently applied units (network, data, apps) so one mistake can't take down everything.
8. **Secrets are not in code** — reference a secrets manager; state files may contain secrets and must be protected (`03-state_and_remote_backends/`).

## 5. GitOps

GitOps extends IaC: **Git is the single source of truth**, and an automated agent continuously reconciles the live system to match the repository (pull-based: Argo CD/Flux for Kubernetes; push-based: CI running `terraform apply` on merge). Rolling back = reverting a commit.

## Under the Hood: How a Declarative Engine Works

Every declarative IaC tool runs the same loop:

1. **Parse** the configuration into a set of desired resources with attributes.
2. **Build a dependency graph** from references between resources (a subnet references a VPC's ID → the VPC must exist first). Independent resources can be created in parallel.
3. **Read the current state** — what the tool believes exists (Terraform's state file / CloudFormation's stack) — and **refresh** it by asking the provider's API what really exists.
4. **Diff** desired vs current, per resource: create, update in place, replace (destroy + create, when an immutable attribute changes, e.g. an RDS instance's engine), destroy, or no-op.
5. **Apply** the diff in dependency order (reverse order for destroys), recording results in state as each operation completes.

That's why the same code is safe to re-run, why a plan can show "must be replaced" warnings, and why losing or corrupting the state file is serious: without it the tool no longer knows which real resources it owns.

![ClickOps produces drift and snowflakes; with IaC, code in Git is reviewed, planned against current state, and applied by an engine that builds a dependency graph, diffs desired versus actual, and creates, updates or replaces resources](diagrams/01-iac-loop.svg)

## Common Pitfalls

1. **Mixing manual console changes with IaC** — drift and surprise destroys on the next apply.
2. **One giant configuration for everything** — slow plans, huge blast radius.
3. **Applying without reading the plan** — "replace" on a database means data loss.
4. **Secrets hard-coded in IaC files** or unprotected state.
5. **Copy-pasting environments** instead of parameterizing one codebase.
6. **Treating IaC as "write once"** — it needs reviews, tests and upgrades like any code.

## Quick Reference

```
IaC = infrastructure described in versioned code, applied by a tool
declarative: describe end state → tool computes plan → idempotent applies
principles: VCS + review · plan before apply · immutable · same code per env · no manual changes · small blast radius · no secrets in code
tools: Terraform/OpenTofu (multi-cloud) · CloudFormation/CDK (AWS) · Pulumi · Ansible (config) · K8s manifests
```
