Infrastructure as Code: Terraform Fundamentals and State
Provision cloud infrastructure declaratively with Terraform - providers, resources, state, plan/apply, and idempotency
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 withapply, and reverse withdestroy - Terraform State - Explain what the state file tracks and why it is critical
- Idempotency - Understand why running
applytwice 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 planand 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
applyon 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.0version constraint mean? - How does a data source differ from a resource?
⚡ Quick Wins and Checkpoints
- Config written: You have a
main.tfwith 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 statecommands 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 plando thatapplydoes 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
applyon 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.tfwith a provider and one resource - Run
init,plan,apply, thendestroy - 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.tfwith at least two variables (one with a default) - The resource references
var.values - An
outputs.tfexposing the bucket ARN - Apply passing the bucket name via
-var, then read it back withterraform 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.tfstatefile 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:
- 🎯 Kubernetes Fundamentals - Orchestrate containers atop the infrastructure you now automate
Explore Side Adventures:
- ⚔️ AWS Essentials - Revisit the services you are now automating
- ⚔️ Azure Ascension - Apply IaC thinking to a managed platform deploy
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
- Terraform Documentation - The complete official reference
- Terraform AWS Provider - Every AWS resource and data source
- Terraform State - How state works and why it matters
- HCL Configuration Language - Syntax and semantics of
.tffiles
Community Resources
- OpenTofu - The open-source, drop-in fork of Terraform
- Terraform Registry - Providers and reusable modules
- Stack Overflow: terraform tag - Community Q&A
Learning Materials
- HashiCorp Learn: Terraform Tutorials - Free, hands-on guided tutorials
- Terraform: Get Started on AWS - The official AWS quickstart
🤝 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
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
Click a node to open the quest · ⌘/Ctrl-click for a new tab · drag to reposition · scroll to zoom.
Referenced by
- Loading…