Installing Terraform & Your First Configuration
Terraform / Infrastructure as Code
Chapter 2 · Installing Terraform & Your First Configuration
Chapter 1's resource block was a preview. This chapter installs the real CLI and runs an actual configuration end to end — deliberately using a provider that needs no cloud account or credentials, so the workflow itself is the entire focus.
Installing Terraform
Terraform ships as a single binary — download it from HashiCorp's releases, or install via a package manager (brew install terraform on macOS, choco install terraform on Windows, or an apt/dnf repository on Linux). Verify the install:
The terraform and provider Blocks
Every configuration starts with a terraform block declaring which providers it needs, and a provider block configuring one of them. A provider is a plugin that knows how to talk to a specific system — AWS, Azure, a local filesystem, even things like GitHub or Cloudflare all have providers.
terraform init
init reads the required_providers block, downloads the matching provider plugin(s) into a local .terraform/ directory, and initializes the backend (by default, a plain local state file — remote backends are Chapter 6's own topic).
The Dependency Lock File
init also writes .terraform.lock.hcl, recording the exact provider version and checksum actually installed. This is the same idea as node1-2's package-lock.json or ruby2-7's Gemfile.lock: it guarantees everyone running init against this configuration gets the identical provider build, not just "something matching the version constraint."
- Commit
.terraform.lock.hclto git — it's what makes provider versions reproducible across machines and teammates - Never commit
.terraform/— it's a local download cache, regenerated byiniton any machine, exactly likenode_modules/or a Rusttarget/directory
Provider Version Pinning
The version = "~> 2.5" constraint means "any 2.5.x release, but not 2.6.0 or higher." Pinning matters for the same reason the lock file does — an un-pinned provider could silently pick up a newer version with different behavior, producing configuration drift of its own, this time in the tool itself rather than the infrastructure it manages.
The resource Block In Depth
A resource has the shape resource "<type>" "<local name>" { ... }. The type (local_file) is defined by the provider; the local name (hello) is how this configuration refers to it. Together they form a unique resource address, local_file.hello, used throughout the rest of the configuration and in CLI commands.
terraform plan
Run plan before ever applying — it shows exactly what will change, using + for create, - for destroy, and ~ for update-in-place.
terraform apply
apply re-runs the same plan and, after an interactive confirmation, executes it.
hello.txt now exists on disk. Run terraform plan again with nothing changed, and it reports "No changes" — the same idempotency property from Chapter 1's Exercise 1, now demonstrated for real.
terraform destroy
Tears down everything this configuration manages, in dependency order, after its own interactive confirmation.
local provider needs no account, no credentials, and no cost — deliberately chosen here so the workflow itself (init → plan → apply → destroy) is what gets practiced first, before real cloud providers enter the picture.
provider "aws" {}) should read credentials from environment variables or a credentials file — never write an access key directly into a .tf file. Exactly the rule pipelines1-5 and crypto1-11 already established: a committed credential is compromised the moment it's pushed, permanently, even if later removed.
Hands-On Exercises
After applying the hello.txt example, running terraform plan again with nothing changed prints "No changes." Explain what this output confirms about the workflow, connecting it back to Chapter 1's idempotency exercise.
Explain why .terraform.lock.hcl should be committed to git while the .terraform/ directory should not, drawing the parallel to another ecosystem's own lock-file convention.
A colleague writes provider "aws" { access_key = "AKIA..." secret_key = "..." } directly in a committed .tf file. Explain why this is dangerous and what to do instead.
Chapter 2 Quick Reference
terraform init— downloads providers, initializes the backend, writes the lock fileterraform plan— shows what would change (+/-/~), changes nothingterraform apply— executes the plan after confirmationterraform destroy— tears down every managed resource- Commit
.terraform.lock.hcl— never commit.terraform/ - Never hardcode credentials in a provider block — use environment variables or a credentials file