Title: Lecture 6 — Infrastructure as Code and the Terraform Workflow
Course: AIINFRA 303: Capstone Project > Section: Week 06 — Deploying to the Cloud with Infrastructure as Code

📖 Lecture — Infrastructure as Code and the Terraform Workflow

Up to this point in the certificate, you have provisioned things by hand: clicking through a cloud console, running one-off CLI commands, SSHing into a box to install a package. That works for a demo. It does not work for a production capstone that you need to rebuild, hand off, or scale. This week you adopt Infrastructure as Code (IaC): the practice of defining your servers, storage, networking, and permissions in text files that live in version control, rather than in a human's memory of which buttons they clicked.

Declarative and idempotent — the two words that matter

Terraform, the tool we'll use, is declarative. You do not write a script that says "create a bucket, then create a Lambda, then wire them together." Instead you declare the end state you want — "there should exist an S3 bucket named X, a Lambda function named Y, subscribed to that bucket" — and Terraform figures out the steps to get there. This is a fundamentally different mental model from the imperative shell scripts you may have written in earlier weeks. Terraform is also idempotent. Running terraform apply twice in a row with no changes to your .tf files produces no changes to your infrastructure — Terraform compares your declared state against what actually exists and only acts on the difference (the drift). This is what makes IaC safe to re-run: you are never accumulating duplicate resources or fighting against a script that assumes a clean slate.

The plan → apply workflow

Terraform's core workflow has three commands, and the order is not optional:

Command | What it does | Why it matters
terraform init | Downloads the provider plugins (e.g., the AWS provider) and sets up the backend | Run once per project/clone, and again after adding a new provider
terraform plan | Computes the diff between your .tf files and real infrastructure, and prints it without changing anything | Your safety net — always read the plan before applying
terraform apply | Executes the plan, creating/modifying/destroying only what has drifted | The only command that actually touches infrastructure

terraform plan is the step most beginners skip, and it's the one that saves you. It shows you a colored diff — green for additions, red for destructions, yellow for in-place modifications — before anything happens. If a plan says it's about to destroy your database, you want to see that sentence before you type yes, not after.

Why this replaces console clicking

Because your infrastructure definition is a text file, it goes through the same lifecycle as your application code: it's committed to Git, it can be code-reviewed in a pull request, and it has history. If someone asks "why does this security group allow port 22 from anywhere," you can run git blame on the .tf file and find out. If a change breaks staging, you can git revert the commit and terraform apply your way back to the previous known-good state — a one-command rollback that a console click trail can never give you. This is the same version-controlled, reviewable discipline you've applied to application code since Week 1; now it extends to the infrastructure underneath it.

Credentials: Terraform borrows your AWS CLI chain

Terraform's AWS provider does not invent its own credential system. It walks the same credential chain the AWS CLI uses: environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY), shared credentials files (~/.aws/credentials), or an attached IAM role. Set your credentials as environment variables (or configure an AWS CLI profile) before you run terraform apply — Terraform will find them automatically; you do not paste keys into your .tf files (and definitely never commit them).

Addressing the misconceptions directly

"Cloud resources are free until I do something with them." False — cloud compute and storage typically bill by the hour whether or not you're actively using them. A t2.micro EC2 instance or an RDS database left running over a weekend racks up charges even while idle. This week, because you're targeting LocalStack (a local Docker container that emulates AWS APIs), your lab work costs nothing. If you do the optional stretch goal against real AWS, set a billing alert first and run terraform destroy the moment you're done testing. "The cloud is secure by default." Also false, and dangerously so. Gartner estimates that roughly 80% of cloud data breaches trace back to misconfiguration — an open SSH port to the whole internet, a public S3 bucket, an IAM policy that grants far more than it needs — not to a flaw in the cloud provider's own security. Security is a shared responsibility: the provider secures the underlying platform, but you are responsible for how you configure what you provision. Default to least privilege and private-by-default storage every time. "I'll just set it up by hand once and remember what I did." This is how environments drift — dev, staging, and prod quietly diverge because someone clicked one extra checkbox in one of them and never wrote it down. IaC forces every environment to be built from the same declared source, so "it works in staging but not prod" becomes a diffable, debuggable problem instead of a mystery. This week's lab puts all of this into practice: you'll write real Terraform, watch a real plan/apply cycle, and provision your capstone's infrastructure with no console clicks at all.