Sheets Terraform
Cheat sheet
Terraform
Format, plan, state, import, and the S3 backend settings that keep apply from stepping on itself.
Commands are Terraform 1.5 or newer unless a section says otherwise. Run them from the directory that contains the .tf files, or pass -chdir.
terraform -chdir=infra/network plan
Format, init, validate
terraform version
terraform fmt -recursive
terraform fmt -check -diff -recursive
terraform init
terraform validate
fmt rewrites files. -check only reports which files would change, which is what CI should run. validate checks syntax and types and needs terraform init first so providers and modules are installed.
terraform init -upgrade
terraform providers lock -platform=linux_amd64 -platform=darwin_arm64
Commit .terraform.lock.hcl. Do not commit the .terraform/ directory or terraform.tfstate. State often contains secrets and resource ids.
Plan and apply
terraform plan -out=tfplan
terraform show tfplan
terraform apply tfplan
Applying a saved plan does not prompt, and it refuses to run if the state changed after the plan was created. terraform show tfplan prints the plan again so you can read it without re-planning.
A
.tfplanfile can contain sensitive values. Do not commit it.terraform apply -auto-approveskips the prompt when you did not save a plan. Leave it off when a person is at the keyboard.
terraform plan -destroy -out=tfplan
terraform destroy
plan -destroy is the reviewable version. terraform destroy asks for confirmation and then destroys what is in state.
Replace one resource instead of tainting it. terraform taint is obsolete.
terraform apply -replace='aws_instance.web'
State
terraform state list
terraform state show aws_instance.web
terraform state pull
terraform state pullprints the state, secrets included. Do not redirect it into the repository.
terraform state rm aws_s3_bucket.logs
state rm forgets the object. It does not delete it in the cloud. If the configuration still declares that resource, the next apply will try to create it again.
terraform force-unlock LOCK_ID clears a stuck lock. Only run it when you are sure no apply is still writing.
Import
The resource block has to exist in configuration before a classic import, or the next plan will want to destroy the imported object.
terraform import aws_s3_bucket.logs example-prod-logs
Terraform 1.5 and newer can declare the import and generate configuration.
import {
to = aws_s3_bucket.logs
id = "example-prod-logs"
}
terraform plan -generate-config-out=generated.tf
Read generated.tf before trusting it. Generated arguments often need a pass to match the style of the rest of the module.
Variables and outputs
variable "region" {
type = string
description = "AWS region for this stack."
default = "us-east-1"
}
output "bucket" {
value = aws_s3_bucket.logs.bucket
}
terraform plan -var='region=us-west-2' -var-file=prod.tfvars
export TF_VAR_region=us-east-1
terraform output
terraform output -raw bucket
Highest precedence wins: -var and -var-file, then *.auto.tfvars, then terraform.tfvars, then TF_VAR_ environment variables, then the variable’s default. output -raw is for string outputs. It prints the value with no extra quotes.
prod.tfvarsand*.auto.tfvarsare loaded from disk. Do not commit a tfvars file that holds secrets.terraform.tfvarsis a common local-only file.
Workspaces
terraform workspace list
terraform workspace show
terraform workspace new staging
terraform workspace select staging
A workspace is a separate state name on the same backend. It is not, by itself, an account boundary or a permissions boundary.
Backend
On Terraform 1.10 and newer, lock state in S3 itself. dynamodb_table still works and is deprecated.
terraform {
required_version = ">= 1.10.0"
backend "s3" {
bucket = "example-tf-state"
key = "prod/network/terraform.tfstate"
region = "us-east-1"
encrypt = true
use_lockfile = true
}
}
Changing backend settings means running terraform init again. Terraform will offer to copy existing state when it can.
A small resource
resource "aws_s3_bucket" "logs" {
bucket = "example-prod-logs"
}
Bucket names are global. An example- prefix will collide with someone else’s bucket; use a name you own.