20 part series

Terraform From Basics to Real-World Practice

Learn Terraform from zero to standing up multi-environment AWS infrastructure through CI/CD. The series covers HCL, providers and resources, state and remote state on S3, variables and expressions, modules, multiple environments, lifecycle, testing and pipelines — closing with a complete capstone project. Every command runs for real on AWS, code lives at github.com/nghiadaulau/terraform-series. Grounded in HashiCorp's official docs, Terraform 1.15 and AWS provider v6.

1

Infrastructure as Code, What Terraform Is, and Getting to Know the CLI

The series opener: why managing infrastructure by hand eventually breaks, what Infrastructure as Code solves, and where Terraform fits in that picture. We dissect the core and provider architecture, install Terraform 1.15, and tour the main CLI commands.

Kai··9 min read·DevOpsAWS
2

Provider, Your First Resource, and the init plan apply destroy Lifecycle

Stand up your first real AWS resource: declare a provider and pin its version, create an S3 bucket, then walk the full init → plan → apply → destroy cycle. What each command does inside, why plan writes 'known after apply', what state stores, and why a second apply creates nothing new.

Kai··9 min read·DevOpsAWS
3

HCL Inside Out: Blocks, Data Types, Expressions

Dissect the HCL language thoroughly: what a block is made of, the string/number/bool/list/map/null data types, expressions and functions, string interpolation. Use terraform console to try things directly, and see what else the terraform{} block can declare.

Kai··7 min read·DevOpsAWS
4

State: What Terraform Stores, Why It's Needed, and Drift

Dig into the state file: why Terraform needs it instead of asking AWS directly each time, what exactly it stores, and the refresh mechanism that compares config, state and reality three ways. Create drift by hand with the AWS CLI then watch Terraform detect it, and the difference between a normal plan and plan -refresh-only.

Kai··7 min read·DevOpsAWS
5

The Dependency Graph: Implicit, depends_on, and -target

Terraform infers the order of creating and deleting resources from a dependency graph. This article dissects that graph: implicit dependencies arise from references, viewing it directly with the graph command, why destroy reverses the order, when you need depends_on, and why -target is only an escape hatch.

Kai··6 min read·DevOpsAWS
6

Remote State on S3 With use_lockfile

State sitting on your personal machine can't be shared, isn't safe, and two people running at once will overwrite each other. This article moves state to S3: bootstrap a bucket with versioning and encryption, configure the backend, and enable state locking with use_lockfile — the current approach replacing the deprecated DynamoDB. With a real lock-conflict demo.

Kai··7 min read·AWSS3
7

State Operations: import Block, state mv, state rm

Working with state day to day: bring existing infrastructure under management with the import block and auto-generate configuration with -generate-config-out, rename a resource in state with state mv, and remove a resource from management without deleting it with state rm. All run live against a bucket built by hand beforehand.

Kai··6 min read·DevOpsAWS
8

Secrets: sensitive, ephemeral, and Write-Only Arguments

State stores secrets in plaintext — this article tackles exactly that. sensitive only hides output but still writes to state; ephemeral resources and write-only arguments (Terraform 1.10/1.11) actually keep secrets out of state. Live demo: with the same password, the old way leaks into state while write-only does not.

Kai··6 min read·SecurityAWS
9

Variables, Outputs, Locals and Catching Bad Values Early

Parameterize configuration so the same code runs for multiple environments: variables take input, outputs return results, locals name derived expressions. More important is catching errors early — validation blocks bad input right at plan, precondition and postcondition check assumptions around each resource.

Kai··6 min read·DevOpsAWS
10

Data Sources, Functions, for Expressions and Dynamic Blocks

Read existing information on AWS with data sources (latest AMI, available zones, current account), transform and filter data with for expressions, then generate repeated nested blocks with dynamic blocks. A security group with ingress rules auto-generated from a list of ports serves as the running example.

Kai··5 min read·DevOpsAWS
11

count and for_each: The Index Trap, Conditionals, templatefile

Two ways to create multiple resources: count by index and for_each by key. This article shows the real-world trap of using count with a list — dropping a middle element shifts the indexes and wrongly destroys-and-recreates a whole row of resources — with a live demo, then shows how for_each avoids it. Plus conditional resource creation and templatefile.

Kai··6 min read·DevOpsAWS
12

Writing Your First Module

A module packages a group of resources behind a clean input/output interface, to reuse in many places without copying code. This article writes a 'secure-bucket' module that wraps an S3 bucket along with versioning, encryption and public-access blocking into a single concept, then calls it twice from the root with different inputs.

Kai··5 min read·DevOpsAWS