Objectives 6 & 7 — What the Exam Tests
Objectives 6 and 7 together cover the full lifecycle of Terraform state — how it's stored, protected, synchronized, and inspected — plus hands-on infrastructure maintenance skills like importing existing resources and debugging with verbose logging. Objective 6 dives into local vs. remote backends, state locking (including DynamoDB integration for S3), detecting and resolving configuration drift with -refresh-only, and state manipulation commands. Objective 7 covers importing pre-existing infrastructure (both the modern import block and the legacy CLI command), state inspection commands, and the TF_LOG family of environment variables. Together these objectives represent heavily tested, practical day-to-day Terraform skills.
Core Concepts at a Glance
Six foundational pillars of state management and infrastructure maintenance
Local vs. Remote Backends
The local backend writes terraform.tfstate to disk — simple but unsuitable for teams. Remote backends (S3, GCS, AzureRM, HCP Terraform) store state centrally, enable team collaboration, and support encryption and versioning.
State Locking
Terraform acquires a lock before any operation that modifies state (apply, destroy) to prevent concurrent corruption. S3 uses a DynamoDB table; HCP Terraform has built-in locking. The local backend does NOT lock by default.
Drift Detection & Refresh
Drift occurs when real infrastructure diverges from Terraform state due to out-of-band changes. terraform plan reveals drift. terraform apply -refresh-only updates state to match reality without altering infrastructure.
moved & removed Blocks
The moved block renames/moves a resource in state without destroy-and-recreate. The removed block (Terraform 1.7+) removes a resource from state management without destroying it in the cloud provider.
Importing Existing Infrastructure
The import block (Terraform 1.5+) is the recommended approach — it can generate config with -generate-config-out. The legacy terraform import CLI command requires you to manually write the resource block first.
Verbose Logging with TF_LOG
Set TF_LOG to TRACE, DEBUG, INFO, WARN, or ERROR to control log verbosity. Combine with TF_LOG_PATH to write logs to a file. Crash logs are auto-saved to crash.log.
Objectives 6 & 7 Quick Reference
| Objective | Sub-Objective | Key Commands / Concepts |
|---|---|---|
| 6a | Local backend | terraform.tfstate, terraform.tfstate.backup, no locking, .gitignore |
| 6b | State locking | DynamoDB for S3, terraform force-unlock, automatic on apply/destroy |
| 6c | Remote backends | backend "s3" block, -reconfigure, -migrate-state, partial config |
| 6d | Drift & state ops | -refresh-only, moved, removed, state list/show/mv/rm |
| 7a | Import infra | import {} block, terraform import CLI, -generate-config-out |
| 7b | Inspect state | state list/show/pull/push, terraform show |
| 7c | Verbose logging | TF_LOG, TF_LOG_PATH, TF_LOG_CORE, TF_LOG_PROVIDER, crash.log |
Deep Dive — Objectives 6 & 7
Detailed coverage of all exam sub-objectives with syntax, nuance, and edge cases
Objective 6a — Local Backend
Default State Storage
When no backend block is configured, Terraform defaults to the local backend. State is written to terraform.tfstate in the working directory. A backup copy (terraform.tfstate.backup) is created before each state update so you can recover from a failed apply.
- State file is plain JSON — contains resource attributes, including secrets
- No built-in locking — two concurrent applies can corrupt state
- Not practical for teams — each developer has their own local copy
- Always
.gitignorestate files: they contain sensitive data (passwords, private keys) - Suitable for learning and solo development only
Objective 6b — State Locking
Why Locking Matters
Without locking, two engineers running terraform apply simultaneously can interleave writes and corrupt the state file. Terraform automatically acquires a lock before any operation that modifies state: apply, destroy, state mv, and others.
- Local backend: does NOT lock by default
- S3 backend: requires a DynamoDB table — add
dynamodb_table = "terraform-locks"to the backend block - HCP Terraform / Terraform Cloud: built-in locking, no extra config needed
- GCS, AzureRM: native locking support via blob leases / GCS locks
- Not all backends support locking — check provider docs
force-unlock
If Terraform crashes mid-apply, it may leave a stale lock. Use terraform force-unlock <lock-id> to manually release it. The lock ID is displayed in the error message when a lock cannot be acquired.
- Use with caution — only release a lock when you are certain no other process holds it
- The lock ID is a UUID generated at lock acquisition time
- Running
force-unlockon an active lock can corrupt state
Objective 6c — Remote State with Backend Block
S3 Backend Configuration
The most common remote backend on the exam. The backend block lives inside the terraform {} block:
terraform { backend "s3" { bucket = "my-tf-state" key = "prod/terraform.tfstate" region = "us-east-1" dynamodb_table = "terraform-locks" encrypt = true } }
bucket: S3 bucket name (must exist before init)key: path within bucket (use workspace-aware paths in multi-env setups)dynamodb_table: enables state locking via DynamoDBencrypt = true: enables server-side encryption of state
Common Backends
| Backend | Use Case | Locking |
|---|---|---|
s3 | AWS teams | DynamoDB table |
azurerm | Azure teams | Blob lease |
gcs | GCP teams | GCS object lock |
http | Custom REST API | Optional (via API) |
kubernetes | K8s secret storage | Lease-based |
consul | HashiCorp stack | Consul locks |
Init Flags for Backend Changes
terraform init -reconfigure: re-initializes the backend without migrating state; use when you change backend config but DON'T want to migrate existing stateterraform init -migrate-state: migrates state from the old backend to the new backend configuration- Partial configuration: sensitive values (credentials, tokens) can be omitted from the backend block and supplied via
-backend-config="key=value"CLI flags or env vars at init time — keeps secrets out of VCS
Objective 6d — Resource Drift & State Management
Detecting and Resolving Drift
Drift occurs when someone manually changes infrastructure outside of Terraform (e.g., resizing an instance in the AWS console). Terraform state no longer matches reality.
terraform plan: highlights drift as differences between state and provider-reported attributesterraform apply -refresh-only: updates state to match real infrastructure WITHOUT making any infrastructure changes — replaces the deprecatedterraform refreshcommandterraform refresh: deprecated in Terraform 1.x; always prefer-refresh-onlyflag
The moved Block
When you rename a resource in your config, Terraform would normally destroy the old one and create a new one. The moved block records the rename so Terraform updates state without recreating the resource:
moved {
from = aws_instance.old_name
to = aws_instance.new_name
}- Works for module moves too:
from = aws_instance.foo→to = module.web.aws_instance.foo - Can be committed and then removed in a follow-up PR once all state is updated
- Does NOT destroy or recreate the resource
The removed Block (Terraform 1.7+)
Removes a resource from Terraform state management without destroying the actual cloud resource:
removed { from = aws_instance.example lifecycle { destroy = false } }
destroy = false: Terraform stops tracking the resource but leaves it runningdestroy = true(default if omitted): destroys the resource and removes from state- Useful when handing off a resource to another team's Terraform config
State CLI Commands
| Command | Purpose | Destructive? |
|---|---|---|
terraform state list | List all tracked resources | No |
terraform state show <addr> | Show all attributes of one resource | No |
terraform state mv <src> <dst> | Rename/move resource in state | Modifies state |
terraform state rm <addr> | Remove from state (does NOT destroy) | Modifies state |
terraform state pull | Download and print state JSON to stdout | No |
terraform state push <file> | Upload local state file to remote (dangerous) | Overwrites remote |
Key distinction: terraform state rm stops Terraform from managing a resource — it does NOT call the provider's destroy API. The resource keeps running. To actually delete the resource, use terraform destroy.
Objective 7a — Importing Existing Infrastructure
Modern: import Block (Terraform 1.5+)
The recommended approach. Declare an import block in your config:
import { to = aws_instance.example id = "i-1234567890abcdef0" }
- Run
terraform planto preview the import, thenterraform applyto execute - Add
-generate-config-out=generated.tftoterraform plan— Terraform auto-generates the resource block (experimental but useful) - After applying, remove the
importblock — it's a one-time operation - Import ID format varies by resource type — always check the provider documentation
Legacy: terraform import CLI Command
terraform import aws_instance.example i-1234567890abcdef0
- Requires writing the resource block in config before running the command
- Does NOT auto-generate config — you must manually write all attributes
- Imports directly into state; subsequent plan may show drift if config is incomplete
- Still valid and supported but the import block approach is preferred
Objective 7b — CLI to Inspect State
State Inspection Commands
terraform state list: lists all resource addresses tracked in state; use-id=<real-resource-id>to filter by actual provider resource IDterraform state show <address>: prints all attributes of a single resource in human-readable formterraform state pull: downloads and prints the current state as raw JSON to stdout — useful for scripting or manual inspectionterraform state push <file>: manually uploads a state file to the remote backend — overwrites remote state, use with extreme cautionterraform show: shows the current state (or a saved plan) in human-readable formterraform show terraform.tfplan: shows the contents of a saved plan file
Objective 7c — Verbose Logging
TF_LOG Environment Variable
Set TF_LOG before running any Terraform command to enable detailed logging output to stderr:
| Level | Verbosity | Use When |
|---|---|---|
TRACE | Most verbose | Deep debugging — HTTP requests, gRPC calls, provider plugin communication |
DEBUG | Verbose | Step-by-step execution flow, variable resolution |
INFO | Informational | General operational messages |
WARN | Warnings only | Non-fatal issues you should know about |
ERROR | Least verbose | Fatal errors only |
TF_LOG=TRACE terraform apply— maximum logging to stderrTF_LOG_PATH=/tmp/terraform.log— redirects logs to a file (in addition to or instead of stderr)TF_LOG_CORE— sets log level for Terraform core separatelyTF_LOG_PROVIDER— sets log level for provider plugins separatelyTF_LOG=""— disables logging entirelycrash.log: auto-generated in the working directory on a Terraform panic — always include when filing bug reports with HashiCorp
Memory Hooks
Six sticky mental models to anchor state management concepts for exam day
Backend Basics
The local backend stores state on your laptop — no locking, no sharing. The moment a second person joins the project, move to a remote backend. Think of local as a single-player save file and remote as a shared cloud save.
S3 + DynamoDB
S3 stores the state file; DynamoDB stores the lock record. Without DynamoDB, the S3 backend has no locking. Remember: one service stores the state, a separate service guards access to it.
moved vs. removed
moved tells Terraform "this resource is now called something else — don't recreate it." removed tells Terraform "stop tracking this — but leave it running." Two very different state surgery operations.
Log Level Order
Remember the order: T-D-I-W-E from noisiest to quietest. Use a mnemonic: "Totally Detailed, I Want Everything". TRACE floods your terminal; ERROR only shows fatal issues.
Refresh-Only Mode
-refresh-only is a read-only pass — it queries providers and updates your state file to match what actually exists, without touching any real infrastructure. It replaced the deprecated terraform refresh command.
Import Methods
The modern import block can auto-generate resource config with -generate-config-out. The legacy terraform import CLI demands you write the resource block manually before it will add state. New approach = more automation.
Practice Quiz
10 questions · Objectives 6 & 7 · Click an answer to check
aws_instance.web to aws_instance.webserver in your config. Which approach prevents Terraform from destroying and recreating the resource?terraform state rm aws_s3_bucket.logs. What is the result?terraform plan, causes Terraform to automatically generate HCL configuration for resources being imported using an import block?terraform init flag should you use?terraform state show and terraform state list?Flashcards
Click a card to flip it and reveal the answer. 8 cards covering state management and infrastructure maintenance.
from = aws_instance.old
to = aws_instance.new
}
Terraform updates the state entry to the new address without calling destroy or create on the provider.
TRACE: HTTP calls, gRPC, plugin details. DEBUG: execution flow. INFO: general ops. WARN: non-fatal. ERROR: fatals only. Set TF_LOG="" to disable.
terraform refresh: deprecated in Terraform 1.x. Updated state without a plan step. Always prefer -refresh-only.
terraform state rm only removes the resource entry from the Terraform state file — it does NOT call any provider destroy API. The resource continues to exist in the cloud provider, but Terraform stops managing it.The legacy terraform import CLI requires you to write the full resource block before running the import. No config generation is possible.
Study Advisor
Select a topic area to get targeted study tips and exam focus points
🗃️ State Backends — Exam Focus
- Know that the local backend is the default — no backend block needed, state goes to
terraform.tfstate - Memorize the S3 backend block attributes:
bucket,key,region,dynamodb_table,encrypt - Understand partial configuration: omit credentials from the backend block and supply via
-backend-configflags or environment variables at init time - Know the difference between
-reconfigure(re-init, no migration) and-migrate-state(re-init + move state) - Common backends to recognize:
s3,azurerm,gcs,http,kubernetes,consul - The
cloudblock is the alternative tobackendfor HCP Terraform — covered in Page 5 - Always
.gitignorestate files — they contain sensitive values like passwords and private keys
🔒 State Locking — Exam Focus
- Locking is automatic for write operations (apply, destroy) — you don't have to do anything to enable it once the backend supports it
- The local backend does NOT lock — this is a key exam distractor
- S3 locking requires a separate DynamoDB table — the table name goes in
dynamodb_table = "..."inside the backend block - HCP Terraform has built-in locking — no DynamoDB or extra config needed
- The command to release a stuck lock is
terraform force-unlock <lock-id> - The lock ID appears in the error message when Terraform cannot acquire the lock
- Only use force-unlock when you are absolutely certain no other process is holding the lock
🔄 Drift & Refresh — Exam Focus
- Drift = real infra differs from Terraform state due to out-of-band changes
terraform plandetects drift — shows what would change if you appliedterraform apply -refresh-only= sync state to reality, NO infra changes — always prefer thisterraform refreshis deprecated in Terraform 1.x — know it exists but prefer-refresh-only- The
movedblock prevents destroy-and-recreate when renaming resources - The
removedblock (1.7+) removes a resource from state management without destroying the real resource - Key state commands:
state list(all resources),state show <addr>(one resource),state mv(rename),state rm(remove from state, NOT destroy)
📥 Importing Resources — Exam Focus
- Two methods: import block (Terraform 1.5+, recommended) and terraform import CLI (legacy)
- Import block: declare in config → run
terraform plan→ runterraform apply - Add
-generate-config-out=generated.tftoterraform planto auto-generate HCL config for the imported resource - Legacy CLI: you MUST write the resource block in config BEFORE running
terraform import <address> <id> - Import ID format varies by resource — always check provider documentation (e.g., EC2 uses instance ID, IAM Role uses role name)
- After successful import, delete the
importblock from config — it's a one-time operation terraform state pullprints state JSON — useful for scripting;terraform state pushoverwrites remote state (dangerous)
🐛 Debugging — Exam Focus
- TF_LOG levels from most to least verbose: TRACE > DEBUG > INFO > WARN > ERROR
TF_LOG=TRACEgives maximum detail including HTTP calls and provider gRPC communicationTF_LOG_PATH=/path/to/file.logredirects log output to a fileTF_LOG_COREandTF_LOG_PROVIDERallow separate log levels for Terraform core and provider plugins- Set
TF_LOG=""to disable logging - On a Terraform panic,
crash.logis auto-generated in the current working directory - Always include
crash.logwhen filing bug reports — it contains the panic stack trace VERBOSEis NOT a valid TF_LOG level — only TRACE, DEBUG, INFO, WARN, ERROR
Resources
Official documentation and study materials for Objectives 6 & 7
Terraform Backends
Complete reference for all supported backends, backend configuration, and partial configuration patterns.
developer.hashicorp.com →S3 Backend Reference
Detailed S3 backend configuration including DynamoDB locking, encryption, workspace support, and IAM requirements.
developer.hashicorp.com →State: moved Block
Refactoring resources and modules with the moved block — syntax, examples, and multi-version compatibility notes.
developer.hashicorp.com →Import Block
Modern import block syntax, generating config with -generate-config-out, and import workflow best practices.
developer.hashicorp.com →Debugging Terraform (TF_LOG)
Full reference for TF_LOG, TF_LOG_PATH, TF_LOG_CORE, TF_LOG_PROVIDER, and crash log behavior.
developer.hashicorp.com →State Command Reference
Full reference for terraform state subcommands: list, show, mv, rm, pull, push, and force-unlock.
developer.hashicorp.com →Terraform Associate 004 Study Guide
Official HashiCorp exam study guide and objectives list for the Terraform Associate 004 certification.
developer.hashicorp.com →FlashGenius Practice Tests
Full-length Terraform Associate 004 practice exams with timed mode, detailed explanations, and performance tracking.
flashgenius.net/register →