Why teams use it
The same files can be reviewed, stored in version control, and applied again. That makes a second environment less of a memory test. A pull request is a record of who changed the network. A console session usually is not.
Study guide · Core notes
Reference notes for Terraform Associate (004): what the files declare, which command talks to an API, how modules and state behave, and what HCP Terraform adds.
How to read these notes: Items tagged Extra sit outside the 004 objective list, such as CLI workspaces and the older taint command. Learn the unmarked items first. New to the exam? Start with the overview for the format and the eight objectives. These notes follow Terraform 1.12 behavior described by HashiCorp.
Infrastructure as code means you describe infrastructure in files that a tool can create, change, and destroy. The files are the source of truth. A console click that nobody reviewed is not. Terraform's language is declarative: you describe the desired end state, and Terraform works out the actions that get there.
The same files can be reviewed, stored in version control, and applied again. That makes a second environment less of a memory test. A pull request is a record of who changed the network. A console session usually is not.
A provider is a plugin for one API. One configuration can call an AWS provider and an Azure provider, or a cloud provider and an on-premises provider. Terraform does not replace each cloud's products. It gives those APIs one workflow.
The commands stay init, plan, and apply whether the resource is a virtual machine, a DNS record, or a SaaS object. What changes is the provider and the resource type, not the shape of the workflow.
Infrastructure as code does not remove drift by itself. Drift is a real object that changed outside Terraform. The next plan shows that difference only if you apply from the files. A repository nobody runs is documentation, not a control.
Terraform Core does not know how to call a cloud API. Providers do.
| Piece | What it does |
|---|---|
| required_providers | Names the source, such as hashicorp/aws, and a version constraint. terraform init downloads that plugin. |
| Version constraint | ~> 5.0 allows 5.0 and later 5.x releases, and stops before 6.0. ~> 1.2.0 allows patches in 1.2 only. |
| Dependency lock file | .terraform.lock.hcl records the selected provider versions. Commit it for a root module so the next init can select the same builds. |
| provider block | Sets settings such as a region. A second block needs an alias. A resource chooses it with provider = aws.west. |
| State | Maps each resource address to the real object Terraform manages, and stores attributes. It is not a cache you can delete and expect the next plan to be safe. |
terraform init installs providers and modules and configures the backend. terraform init -upgrade selects newer versions that still match the constraints. The .terraform directory is a local cache. Do not commit it.
Write configuration, initialize the working directory, review a plan, then apply. Destroy is the same workflow aimed at removal. Format is a style step you can run at any time before you commit.
| Command | What it answers |
|---|---|
| terraform init | Are the providers, modules, and backend ready in this directory? |
| terraform fmt | Are the files in canonical style? It rewrites whitespace and alignment. It does not validate. |
| terraform validate | Is the configuration syntactically valid and internally consistent? It loads provider schemas and does not call the remote API. Run init first. |
| terraform plan | What would change? It refreshes state by default and prints creates, in-place updates, and destroys. -out saves that plan. |
| terraform apply | Make the change. By default it shows a plan and waits for yes. Applying a saved plan file runs that plan. |
| terraform destroy | Remove the infrastructure this state manages. It is a plan to destroy, then an apply of that plan. |
In a plan, + creates, - destroys, ~ updates in place, and -/+ replaces. A replace destroys and creates because the provider cannot update that argument in place. Deleting a resource block from the configuration, then applying, destroys that one object. terraform destroy targets the whole state for this configuration.
terraform plan does not change remote infrastructure. terraform validate does not tell you whether a cloud API will accept the values. A saved plan can contain sensitive values, so treat the plan file like state.
Most of the exam is reading a block and saying what Terraform will do with it.
A resource block manages an object: create, update, destroy. A data block reads an object that already exists and does not manage it. Refer to an attribute as resource_type.name.attribute. That reference is also an implicit dependency, so Terraform creates the referenced object first.
A variable block is an input. A local is a named expression inside the module. An output publishes a value to the CLI or to a calling module. Types include string, number, bool, list, set, map, object, and tuple. A list is ordered. A set is unique and unordered. A map uses string keys. An object names each attribute's type. A tuple is a fixed sequence of mixed types.
Use depends_on only when no reference expresses the dependency, for example a resource that must exist before another one even though you never read its attributes. create_before_destroy tells Terraform to create the replacement before it destroys the old object, so dependents are not left with a gap.
You can use conditionals, for expressions, and splat expressions such as aws_instance.web[*].id. Built-in functions transform values. You do not define a function body in a .tf file. count addresses by index, so removing an item in the middle can shift later indexes. for_each addresses by key, so the other instances stay put.
| Mechanism | What a failure or a secret does |
|---|---|
| Variable validation | A validation block with a condition and an error_message rejects a bad input. |
| Precondition and postcondition | Lifecycle checks that fail the operation when the condition is false. A postcondition runs after the object exists. |
| check block | Reports a failed assertion and does not, by itself, stop the apply the way a postcondition does. |
| sensitive = true | Redacts CLI output. The value is still stored in state. |
| Ephemeral value | Available during the run and not written to state or the plan. Use it for a secret that must not persist. |
| Write-only argument | A provider argument you can set and cannot read back. Pair it with an ephemeral value so the secret is not stored. |
| Vault | Read the secret from Vault at run time instead of committing it. The Vault provider is the usual Terraform integration. |
Variable values can come from the environment as TF_VAR_name, from terraform.tfvars, from *.auto.tfvars, or from -var and -var-file. Later sources override earlier ones. Command-line flags win. Do not commit a tfvars file that holds secrets.
A module is a directory of Terraform files you call with a module block. The caller sets the child module's input variables as arguments and reads its outputs. Root variables are not visible inside the child. Locals stay in the module that declares them. That boundary is the point of a module: a small interface instead of every variable leaking inward.
| Source | How you pin it |
|---|---|
| Local path | source = "./modules/vpc". There is no version argument. You pin it by the files in the repository. |
| Terraform Registry | source = "namespace/name/provider". Set version to a constraint such as "~> 5.0". |
| Git | A git URL. Select a commit, tag, or branch with a ref query on the source. The version argument is for the registry. |
Changing a module source or version means running terraform init again. A module that creates resources still stores those resources in the root module's state, under an address like module.network.aws_subnet.public. The child module does not get a separate state file unless it is a separate root configuration.
State is the mapping Terraform trusts. Treat the file as sensitive.
With no backend block, Terraform writes terraform.tfstate in the working directory and can keep terraform.tfstate.backup. That is fine for a solo exercise. It is a poor place for a team, because the file is on one computer and it holds attribute values, including sensitive ones.
A backend block, or a cloud block for HCP Terraform, stores state remotely. Locking stops a second operation from writing that state at the same time. After you add or change a backend, run terraform init. Use -migrate-state to copy existing state, or -reconfigure to point at the new backend without copying.
Drift means the real object changed outside Terraform. The next plan refreshes state and proposes edits that move the object back to the configuration. terraform apply -refresh-only updates state to match reality and does not change the infrastructure. Use it when you intend to accept the outside change, not when you want the file to win.
Do not edit state by hand. terraform state list and terraform state show inspect it. A partial backend configuration leaves secrets out of the .tf file and passes them with -backend-config.
Import brings an object that already exists under Terraform's management. An import block names the resource address in to and the existing object's id. terraform plan can then show the import, and terraform plan -generate-config-out can write a starting configuration. The older terraform import command updates state only and does not write the HCL. Neither command destroys the real object. You still review the configuration so the next apply does not immediately change it.
terraform state list prints addresses. terraform state show prints one object's attributes. terraform state rm drops an address from state and leaves the real object in place, which is how you stop managing something without deleting it. terraform state mv renames an address or moves it, for example into a module. Prefer those commands, or a moved block in configuration, to hand-editing the JSON.
Set TF_LOG to TRACE, DEBUG, INFO, WARN, or ERROR when you need a diagnostic. TRACE is the most detailed. TF_LOG_PATH writes the log to a file. Logs can contain secrets and should not be pasted into a ticket. Leave TF_LOG unset for a normal apply.
Extra terraform apply -replace=address forces replacement on the next apply. It replaces the older terraform taint command. The 004 objective list names import, state inspection, and verbose logging, not taint.
HCP Terraform is HashiCorp's hosted service. Older docs call it Terraform Cloud. Community Edition is the Terraform CLI you run yourself.
| Idea | What to remember |
|---|---|
| Workspace | The remote unit of state, variables, and runs. One working directory connects with a cloud block that names the organization and the workspace. |
| Project | A group of workspaces. Use it to organize teams and to set access above a single workspace. |
| Remote run | Plan and apply execute in HCP Terraform, using variables and credentials stored there, instead of only on your laptop. |
| VCS integration | A commit or a pull request can start a run. A speculative plan from a pull request shows the diff without applying it. |
| Governance | Team access, permissions, and policy as code such as Sentinel or Open Policy Agent can block an apply that breaks a rule. |
| CLI workspace Extra | terraform workspace select switches a named local state. It is not an HCP Terraform workspace and it is not a project. |
A cloud block replaces a backend block for HCP Terraform. Initializing after you add it migrates or attaches state. Variables marked sensitive in the workspace are still available to the run. They are not a reason to commit the same secret in git.
terraform plan compares configuration and state with real infrastructure and prints the actions it would take. terraform apply carries those actions out. A plan does not change infrastructure unless you apply it.
No. sensitive = true redacts the value in CLI output and in logs. Terraform still writes it to state. An ephemeral value is the mechanism that is not stored in state or in the plan.
An HCP Terraform workspace is a remote unit of state, variables, and runs, grouped into a project. A CLI workspace is a named state file selected with terraform workspace in one working directory. Objective 8 tests the HCP Terraform workspace.
Provider arguments and HCP Terraform screen names change. When a note and the current HashiCorp documentation disagree, follow the documentation for the Terraform 1.12 behavior the 004 exam describes.
Use the flashcards to check whether you can recall these distinctions.
Exam format, Terraform 1.12, the eight objectives, and a study plan.
Reference notes for providers, the workflow, configuration, modules, state, and HCP Terraform.
40 recall cards in four decks, plus memory notes for workflow, state, and secrets.
200 original questions with custom exams, explanations, and a score report by objective.
Useful companions while you study.
Convert structured data between JSON and YAML with formatting and validation.
Compare two text blocks and highlight added, removed, and changed content.
Generate strong random passwords with custom length, characters, symbols, and security options.
Encode text and files to Base64 or decode Base64 data with UTF-8 support.
NodnWebTools provides general informational, educational, and convenience resources. Calculations, conversions, estimates, and learning materials may contain errors or become outdated. Financial, tax, medical, legal, and travel information is not professional advice. Verify important results and current requirements with qualified professionals or authoritative sources. Protect sensitive files and personal information, review each tool’s privacy limitations, and use only content you are authorized to process. You are responsible for how you use and share results. Study resources are independent and do not guarantee exam success or imply certification-provider endorsement. HashiCorp, Terraform, and HCP Terraform are trademarks of HashiCorp. NodnWebTools is not affiliated with, endorsed by, or sponsored by HashiCorp or IBM.