Terraform
IaC, state, modules, plan/apply workflow.
Theory
Terraform is HashiCorp's Infrastructure as Code tool. You write declarative HCL (HashiCorp Configuration Language) describing the desired state of infrastructure — EC2 instances, VPCs, DNS records, S3 buckets — and Terraform computes the diff against the current state and makes only the necessary API calls to converge.
The workflow: terraform init downloads providers (AWS, GCP, Azure plugins), terraform plan shows what will change (always review before applying), terraform apply makes the changes, terraform destroy tears everything down. State is stored in terraform.tfstate — a JSON file mapping logical resources to real infrastructure IDs.
Remote state storage (S3 + DynamoDB for AWS) is essential for teams: multiple engineers can't share a local .tfstate file. The S3 backend stores state, DynamoDB provides state locking (only one apply at a time). Never commit terraform.tfstate to version control — it contains secrets in plaintext.
Modules are reusable units of configuration. A module encapsulates resources (e.g. a VPC module that creates subnets, route tables, NAT gateways). Modules are called with input variables and return outputs. The Terraform Registry hosts public modules; internal modules live in shared VCS repos.
Workspaces separate state for different environments (dev/staging/prod) using the same configuration. Alternatively, separate directories or branches per environment provide stronger isolation. Variables (terraform.tfvars, environment-specific .tfvars files, or TF_VAR_ env vars) parameterize configurations across environments.
Import existing infrastructure: terraform import resource.type.name resource_id adds unmanaged infrastructure into state so Terraform can manage it going forward. Refactoring: terraform state mv renames resources in state without destroying/recreating them — critical when reorganizing module structure.
Providers are Terraform plugins that translate HCL into API calls. The AWS provider alone has 900+ resource types. Provider versioning in required_providers ensures reproducible builds. terraform providers lock generates .terraform.lock.hcl pinning exact provider versions across all team members.
Architecture Diagram
HCL modules + variables
|
terraform plan (diff)
|
State file (S3 + DynamoDB lock)
|
Provider plugins (AWS/GCP/Azure)
|
Live infrastructureExamples
terraform {
backend "s3" {
bucket = "tf-state-prod"
key = "vpc/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "tf-lock"
}
}
terraform init
terraform plan -out=plan.tfplan
terraform apply plan.tfplan
Interview Questions
Why remote state?
Teams need shared, locked state — local .tfstate breaks collaboration and risks secret leaks in git.
terraform import use case?
Bring manually created resources under management without destroy/recreate.
Modules vs workspaces?
Modules reuse config; workspaces share code with separate state — prefer separate dirs for prod isolation.
Drift detection?
Scheduled terraform plan in CI; policy-as-code (Sentinel/OPA) blocks risky applies.
State mv vs destroy?
state mv renames in state without API changes; avoid unnecessary destroy/recreate on refactors.
Provider version pinning?
required_providers + lock file ensures reproducible plans across laptops and CI.
Best Practices
- Treat Terraform config as code with review and CI validation.
- Define SLOs and dashboards before production cutover.
- Document rollback and ownership for on-call.
- Use least privilege for credentials and secrets.
Common Mistakes
- Running Terraform in prod without staging parity.
- No monitoring on golden signals after changes.
- Skipping backup/state export before major upgrades.
- Alert fatigue without actionable runbooks.
Cheat Sheet
Practical Exercises
Configure remote state + locking for a VPC module.
Import existing S3 bucket into Terraform management.
Run plan on PR; apply only on main with approval.