Skip to main content
Settings
Search
Appearance
Theme Mode
About
Jekyll v3.10.0
Environment Production
Last Build
2026-07-02 02:06 UTC
Current Environment Production
Build Time Jul 02, 02:06
Jekyll v3.10.0
Build env (JEKYLL_ENV) production
Quick Links
Page Location
Page Info
Layout quest
Collection quests
Path _quests/1000/infrastructure-as-code.md
URL /quests/1000/infrastructure-as-code/
Date 2025-11-29
Theme Skin
SVG Backgrounds
Layer Opacity
0.6
0.04
0.08

Infrastructure as Code: Terraform Fundamentals and State

Provision cloud infrastructure declaratively with Terraform: providers and resources, the plan/apply lifecycle, state files, variables, and idempotency.

Table of Contents

🔥 Lvl 1000Warrior 🏰 Main Quest 🔴 Hard 120-150 minutes

Infrastructure as Code: Terraform Fundamentals and State

Provision cloud infrastructure declaratively with Terraform - providers, resources, state, plan/apply, and idempotency

Primary Tech
🛠️ terraform
Skill Focus
Infrastructure
Series
Cloud Journey
Author
IT-Journey Team
XP Range
⚡ 3000-3750

Hark, automation Warrior! In the previous quest you clicked and typed your way through the AWS console, summoning servers one command at a time. It worked - but it was a ritual of memory and toil, impossible to repeat exactly and dangerous to hand to another. This quest, Infrastructure as Code, teaches you to inscribe your infrastructure into a spellbook of declarative code, so that an entire environment can be conjured - or banished - with a single incantation.

With Terraform, you describe the world you *want and the tool figures out how to make reality match. Check that description into Git and your infrastructure becomes reviewable, versioned, and reproducible. By the end you will understand providers and resources, the sacred plan-and-apply workflow, the all-important state file, and the principle of idempotency that makes it all safe.*

📖 The Legend Behind This Quest

In the dark age of operations, servers were “pets” - hand-raised, uniquely configured, and irreplaceable. When one fell ill, a sysadmin would log in and nurse it back by hand, and no two machines were ever quite alike. This “snowflake” infrastructure was fragile and unknowable.

Infrastructure as Code ended that age. By describing infrastructure in text files and applying them with tooling, servers became “cattle” - identical, disposable, and rebuildable from source. Terraform, released by HashiCorp in 2014, became the lingua franca of this movement: one declarative language to provision across AWS, Azure, Google Cloud, and hundreds of other providers. This quest teaches you to think declaratively - to describe the destination and trust the tool with the route.

🎯 Quest Objectives

By the time you complete this journey, you will have mastered:

Primary Objectives (Required for Quest Completion)

  • Providers and Resources - Declare a provider and define resources in HCL
  • The plan / apply Workflow - Preview changes with plan, enact them with apply, and reverse with destroy
  • Terraform State - Explain what the state file tracks and why it is critical
  • Idempotency - Understand why running apply twice is safe and produces no extra changes

Secondary Objectives (Bonus Achievements)

  • Variables and Outputs - Parameterize a configuration and expose useful values
  • Remote State - Explain why teams store state remotely with locking
  • Data Sources - Read existing infrastructure without managing it

Mastery Indicators

You’ll know you’ve truly mastered this quest when you can:

  • Read a terraform plan and predict exactly what will be created, changed, or destroyed
  • Explain to a teammate why the state file must never be edited by hand or committed with secrets
  • Re-run apply on an unchanged config and explain why “No changes” appears
  • Refactor hard-coded values into variables without altering the result

🗺️ Quest Prerequisites

📋 Knowledge Requirements

  • Completion of AWS Essentials (the examples provision AWS resources)
  • Comfort with the terminal and editing text files
  • Basic Git for versioning your configurations

🛠️ System Requirements

  • Modern operating system (Windows 10+, macOS 10.14+, or Linux)
  • Terraform installed (or OpenTofu, the open-source drop-in)
  • A cloud account with credentials configured (AWS Free Tier recommended)
  • A text editor with HCL support (VS Code + the HashiCorp Terraform extension)

🧠 Skill Level Indicators

This 🔴 Hard quest expects:

  • You will run real provisioning against a live account and clean it up
  • You are ready to think in terms of desired state, not step-by-step commands
  • Ready for 120-150 minutes of focused, hands-on work

🌍 Choose Your Adventure Platform

You need the Terraform binary and configured cloud credentials. Install the CLI for your OS.

🍎 macOS Kingdom Path

Click to expand macOS instructions ```bash # Install Terraform via the HashiCorp tap brew tap hashicorp/tap brew install hashicorp/tap/terraform terraform version # expect Terraform v1.x # Ensure AWS credentials are configured (from the AWS Essentials quest) aws sts get-caller-identity ```

🪟 Windows Empire Path

Click to expand Windows instructions ```powershell # Install via winget winget install HashiCorp.Terraform terraform version # Confirm cloud credentials are available aws sts get-caller-identity ```

🐧 Linux Territory Path

Click to expand Linux instructions ```bash # Add the HashiCorp apt repo (Debian/Ubuntu) and install wget -O- https://apt.releases.hashicorp.com/gpg | \ sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] \ https://apt.releases.hashicorp.com $(lsb_release -cs) main" | \ sudo tee /etc/apt/sources.list.d/hashicorp.list sudo apt update && sudo apt install terraform terraform version ```

☁️ Cloud Realms Path

Click to expand Cloud/Container instructions ```bash # Run Terraform in a container, mounting your working directory docker run --rm -it \ -v "$PWD":/work -w /work \ -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY -e AWS_DEFAULT_REGION \ hashicorp/terraform:latest version ```

🧙‍♂️ Chapter 1: Providers and Resources - The Vocabulary of HCL

Terraform configurations are written in HCL (HashiCorp Configuration Language). Two nouns dominate: the provider you talk to, and the resources you ask it to manage.

⚔️ Skills You’ll Forge in This Chapter

  • Declaring a provider with version constraints
  • Defining a resource block
  • The difference between resources and data sources

🏗️ Your First Configuration

A provider is a plugin that knows how to talk to a platform (AWS, Azure, GitHub, Cloudflare, and hundreds more). A resource is a single managed object - a bucket, an instance, a DNS record. Create a directory and a file named main.tf:

# main.tf — declare the AWS provider and one S3 bucket

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = "us-east-1"
}

resource "aws_s3_bucket" "quest" {
  bucket = "iac-quest-bucket-change-me-12345"

  tags = {
    Project = "it-journey-quest"
    Managed = "terraform"
  }
}

The syntax resource "<type>" "<local-name>" declares a resource: aws_s3_bucket is the type, and quest is the name you use to reference it elsewhere in your code (e.g., aws_s3_bucket.quest.id).

A data source is the read-only cousin of a resource - it looks up something that already exists rather than creating it:

# Read the most recent Amazon Linux 2023 AMI without managing it
data "aws_ami" "al2023" {
  most_recent = true
  owners      = ["amazon"]

  filter {
    name   = "name"
    values = ["al2023-ami-*-x86_64"]
  }
}

🔍 Knowledge Check: Providers and Resources

  • What is the role of a provider versus a resource?
  • What does the ~> 5.0 version constraint mean?
  • How does a data source differ from a resource?

⚡ Quick Wins and Checkpoints

  • Config written: You have a main.tf with a provider and a resource
  • Vocabulary clear: You can point to the provider, resource, and (optional) data source

🧙‍♂️ Chapter 2: The plan / apply Workflow and State

Terraform never changes your infrastructure blindly. It first computes a plan - a precise diff between the world it sees and the world you want - and only then, on your command, makes it real. The bridge between the two is the state file.

⚔️ Skills You’ll Forge in This Chapter

  • The full init -> plan -> apply -> destroy lifecycle
  • What the state file is and why it matters
  • Why state must be protected and stored remotely for teams

🏗️ The Core Lifecycle

# 1. init: download the provider plugins and prepare the working directory
terraform init

# 2. plan: preview what will change — creates nothing yet
terraform plan

# 3. apply: enact the plan after you confirm with "yes"
terraform apply

# 4. destroy: tear everything in the state back down when done
terraform destroy

A terraform plan is read carefully before every apply. Its symbols are a language:

  +  create        a new resource will be added
  -  destroy       an existing resource will be removed
  ~  update        an attribute will change in place
-/+  replace       the resource must be destroyed and recreated

Plan: 1 to add, 0 to change, 0 to destroy.

🏗️ Understanding State

After apply, Terraform writes a state file (terraform.tfstate) - a JSON record mapping each resource in your code to the real object it created in the cloud. State is how Terraform knows that aws_s3_bucket.quest is the bucket iac-quest-bucket-..., so the next plan can compute an accurate diff instead of trying to recreate everything.

Three rules of state:

  • Never edit it by hand. Use terraform state commands if you must manipulate it.
  • Never commit it to Git if it contains secrets. State can hold sensitive values in plaintext.
  • Store it remotely for teams. A shared remote backend (e.g., an S3 bucket with DynamoDB locking, or Terraform Cloud) gives everyone one source of truth and prevents two people applying at once.
# Example remote backend — state lives in S3, locking via DynamoDB
terraform {
  backend "s3" {
    bucket         = "my-team-tfstate"
    key            = "iac-quest/terraform.tfstate"
    region         = "us-east-1"
    dynamodb_table = "tf-locks"
    encrypt        = true
  }
}

🔍 Knowledge Check: Workflow and State

  • What does terraform plan do that apply does not?
  • What does the state file map together?
  • Name two reasons teams use a remote backend.

🧙‍♂️ Chapter 3: Idempotency, Variables, and Outputs

The deepest magic of Terraform is idempotency - the property that describing a desired state and applying it repeatedly always converges to that same state, with no surprises. Variables and outputs make your spellbook reusable.

⚔️ Skills You’ll Forge in This Chapter

  • The meaning and value of idempotency
  • Parameterizing a configuration with variables
  • Exposing computed values with outputs

🏗️ Idempotency in Practice

Run terraform apply once and your bucket is created. Run it again, with the same config, and Terraform reports:

No changes. Your infrastructure matches the configuration.

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

That is idempotency: the same input always yields the same end state. Because Terraform compares desired state (your code) against actual state (the state file plus a refresh of reality), it only ever does the work needed to close the gap - and if there is no gap, it does nothing. This is what makes IaC safe to run in automation: a pipeline can apply on every commit without fear of duplicating resources.

🏗️ Variables and Outputs

Hard-coded values do not scale. Variables parameterize a config; outputs surface useful results.

# variables.tf — declare inputs
variable "bucket_name" {
  description = "Globally unique name for the quest bucket"
  type        = string
}

variable "region" {
  description = "AWS region to deploy into"
  type        = string
  default     = "us-east-1"
}

# main.tf — use the variable
resource "aws_s3_bucket" "quest" {
  bucket = var.bucket_name
}

# outputs.tf — expose a result for humans and other tools
output "bucket_arn" {
  description = "ARN of the created bucket"
  value       = aws_s3_bucket.quest.arn
}

Pass a variable at apply time, and read the output afterward:

terraform apply -var="bucket_name=iac-quest-$RANDOM"
terraform output bucket_arn

🔍 Knowledge Check: Idempotency and Reuse

  • Why does a second apply on an unchanged config make no changes?
  • How does a variable improve a configuration’s reusability?
  • What is an output good for that a variable is not?

🎮 Mastery Challenges

🟢 Novice Challenge: Create and Destroy

Objective: Write a minimal config that creates one S3 bucket, then destroy it.

Requirements:

  • A main.tf with a provider and one resource
  • Run init, plan, apply, then destroy
  • Confirm the bucket is gone after destroy

Validation: terraform plan after destroy reports nothing to create or change beyond a fresh build.

🟡 Intermediate Challenge: Parameterize It

Objective: Refactor the bucket name and region into variables and expose the bucket ARN as an output.

Requirements:

  • A variables.tf with at least two variables (one with a default)
  • The resource references var. values
  • An outputs.tf exposing the bucket ARN
  • Apply passing the bucket name via -var, then read it back with terraform output

Validation: Changing only the variable value, not the resource block, changes the result.

🔴 Advanced Challenge: Prove Idempotency and Reason About State

Objective: Demonstrate idempotency and explain the role of state in your own words.

Requirements:

  • Apply your config, then apply again and capture the “No changes” output
  • Open the terraform.tfstate file and identify the mapping between your code and the real resource
  • Write a short note on why state must not be hand-edited or committed with secrets
  • Bonus: configure a remote S3 backend and re-init

Validation: You can show a “0 added, 0 changed, 0 destroyed” apply and explain why.

🏆 Quest Rewards & Achievements

🎖️ Badges Earned:

  • 🏆 Forgemaster - You provision infrastructure from declarative code
  • 📜 Keeper of the State Scroll - You understand and protect Terraform state

🛠️ Skills Unlocked:

  • Terraform plan/apply Workflow - Preview and enact infrastructure changes safely
  • Declarative Infrastructure Design - Describe the destination, not the route

🔓 Unlocked Quests:

  • Kubernetes Fundamentals - Provision and orchestrate container clusters
  • Advanced IaC patterns - Modules, workspaces, and multi-environment pipelines

📊 Progression Points: +100 XP

🗺️ Next Steps in Your Journey

Continue the Main Story:

Explore Side Adventures:

Character Class Recommendations

💻 Software Developer: Continue to Kubernetes Fundamentals
🏗️ System Engineer: Master modules and remote state for team workflows
🛡️ Security Specialist: Audit state handling and secret management in your pipelines

📚 Resources

Official Documentation

Community Resources

Learning Materials

🤝 Quest Completion Checklist

  • ✅ Completed all primary objectives
  • ✅ Created and destroyed a resource through the full Terraform lifecycle
  • ✅ Answered all knowledge check questions
  • ✅ Completed at least one mastery challenge
  • ✅ Explored the resource library
  • ✅ Destroyed all billable resources to avoid charges

🕸️ Knowledge Graph

Structured wiki-links connect this quest to the IT-Journey knowledge graph. Open the Obsidian Graph View to explore connections.

Level hub: [[Level 1000 (8) - Cloud Computing]] Overworld: [[🏰 Overworld - Master Quest Map]] Prerequisites: [[AWS Essentials: Core Services and Cloud Architecture Patterns]] Unlocks: [[Kubernetes Fundamentals: Container Orchestration Essentials]] Obsidian docs: [[Obsidian Knowledge Graph and Wiki Links]]

🎁 Rewards

100 XP

Badges

  • 🏆 Forgemaster - Provisioned infrastructure from declarative code
  • 📜 Keeper of the State Scroll - Understands and protects Terraform state

Skills unlocked

  • 🛠️ Terraform plan/apply Workflow
  • 🧠 Declarative Infrastructure Design

Features unlocked

  • The foundation for automating Kubernetes clusters and full cloud stacks

🕸️ Quest Network

Loading quest graph…

Click a node to open the quest · ⌘/Ctrl-click for a new tab · drag to reposition · scroll to zoom.