HashiCorp · Free Practice Questions · Last reviewed May 2026
36 real exam-style questions organised by domain, each with the correct answer highlighted and a plain-English explanation of why it's right — and why the others are wrong.
You are attempting to use a conditional expression to set a variable, but the types returned by the true and false results differ. What happens?
The result is coerced to a string
A type mismatch error is returned
Terraform requires both conditional results to share a compatible type. When the true and false expressions return different types, evaluation fails with a type mismatch error rather than coercing one value, satisfying the stem's scenario.
It defaults to the true result type
Terraform automatically casts to the most flexible type
You have a list of objects representing AWS tags. You need to transform this list into a map for use with a for_each argument. Which function should you use?
tolist()
flatten()
merge()
for expression
A for expression iterates the tag list and builds a map keyed by each element, which for_each requires. It satisfies the transformation constraint directly, unlike a for_each meta-argument or lookup, since it produces the map value rather than consuming one.
In a dynamic block, you need to access the current iteration item. What is the default label assigned to the iterator object?
count.index
The name of the block
When no explicit iterator is declared, Terraform names the iterator object after the dynamic block's label itself, so a block labelled 'ingress' exposes each element as 'ingress.value'. This satisfies the default-label constraint without requiring an iterator argument.
each.value
item
When using for_each on a resource, how do you access the value of the current iteration inside the resource configuration?
each.value
With for_each over a map or set, Terraform exposes each.key and each.value; each.value yields the current element's value, letting the resource configuration reference per-iteration data. This satisfies the need to access the current iteration's value directly within the resource block.
each.key
item.value
count.index
Which function is most useful when you have a nested list of objects and want to create a single flat list to iterate over with for_each?
concat()
flatten()
flatten() collapses nested lists into a single-level list, so a list of lists of objects becomes one flat list of objects. This satisfies the stem's requirement to iterate the result with for_each, which rejects nested collections.
lookup()
merge()
You want to optionally create an S3 bucket only if a specific variable 'create_bucket' is set to true. Which HCL feature is best for this?
conditional expression (ternary)
Setting count = var.enabled ? 1 : 0 is the common pattern for optional resource creation.
try()
dynamic block
for_each
Want more Dynamic HCL Configuration practice?
Practice this domainWhich directory structure is considered standard for a Terraform module?
A directory containing main.tf, variables.tf, and outputs.tf.
Splitting inputs, outputs, and resource declarations into variables.tf, outputs.tf, and main.tf is the documented convention, giving consumers a predictable interface. This satisfies the standard structure expected when a directory is consumed as a reusable module.
One single file named 'all.tf'.
A binary executable file that compiles the infrastructure.
A separate folder for every single resource.
What is the primary benefit of using a module registry compared to a local file path for module distribution?
It allows you to run Terraform commands faster.
It removes the need for input variables.
It automatically converts your code to a higher-level language.
It enables version control and easier sharing across the organization.
A registry provides published, versioned modules that teams can pin and reuse, unlike a local file path which offers no versioning or central distribution. This satisfies the cross-organisation sharing and version-control requirement in the stem.
When refactoring a large infrastructure configuration, you move a resource into a child module. How do you handle the existing state to prevent Terraform from destroying and recreating the resource?
Run 'terraform refresh' to automatically detect the move.
Use the 'terraform state mv' command to move the resource address.
Using `terraform state mv` rewrites the resource's address in the state file from its root-level path to the new child-module path, so Terraform maps the existing remote object to the relocated configuration block. This satisfies the stem's constraint of preventing destroy-and-recreate, since no infrastructure changes are applied.
Rename the resource in the configuration to match the old state.
Delete the state file and run 'terraform apply'.
You have a nested module structure. How can you pass a variable from the root module through an intermediate module to a leaf module?
Define the variable only in the leaf module and refer to root by index.
You must define the variable in the intermediate module and pass it to the leaf module.
Terraform modules have no implicit variable inheritance, so the intermediate module must declare the variable in its own variables block and explicitly forward it via an argument in its module call to the leaf. This explicit pass-through satisfies the root-to-leaf requirement.
You can use the 'global_vars' block in the root.
The intermediate module automatically inherits all root variables.
You are designing a module that should conditionally create resources based on a boolean input. What feature should you use?
Define multiple resources and use 'depends_on' to link them.
Use the 'count' meta-argument with a ternary expression.
The count meta-argument combined with a ternary expression evaluates the boolean to either 1 or 0, creating or omitting the resource instances accordingly. This directly satisfies the stem's requirement for conditional resource creation from a boolean input.
Use an 'if' block around the resource definition.
Use the 'module' meta-argument inside the resource.
You need to output a complex object from a child module to be used by the root module. What is the best practice for defining the output?
Assign the output to a global variable in the root module.
Use a data source to read the child module's internal state.
Define an output block in the child module and reference it in the root module using the module prefix.
Outputs expose values across module boundaries; declaring an output block in the child module and referencing it as module.<name>.<output> in the root module is the standard mechanism. This satisfies the requirement to pass a complex object upward without duplicating logic.
Write the output to a local file inside the module and read it in the root.
Want more Terraform Modules practice?
Practice this domainYou are using HCP Terraform agents. Why would you choose to use an agent instead of the public HCP Terraform execution environment?
To increase execution speed
To access resources in a private network
HCP Terraform agents run inside your own infrastructure, so they can reach endpoints on private networks that the hosted execution environment cannot route to. This directly satisfies the stem's private-network access constraint, which the public runners cannot fulfil.
To bypass OPA policies
To avoid paying for HCP Terraform
You are writing an OPA (Open Policy Agent) policy to restrict resource creation. You want to deny any EC2 instance that does not include the 'CostCenter' tag. How do you access the resource attributes in the policy?
terraform.tags
input.resource_changes
OPA evaluates Terraform plan JSON, where every proposed change appears under input.resource_changes. Each entry carries the resource type, address and planned values, so the policy can inspect the EC2 instance's tags block and deny the run when 'CostCenter' is absent.
state.output
var.tags
When migrating from local state to HCP Terraform, which command is used to initialize the migration?
terraform login
terraform push
terraform init
`terraform init` detects the existing local backend configuration and prompts to migrate state to HCP Terraform's remote backend, copying `terraform.tfstate` to the workspace. This satisfies the migration constraint directly, since no separate import or push command exists for backend transitions.
terraform migrate
Your team is using HCP Terraform. You need to isolate development, staging, and production environments using the same set of configuration files. Which feature should you implement?
Modules
Sentinel Policies
Workspaces
Workspaces let one configuration directory drive multiple, isolated deployments, each holding its own state, variables and run history. Separate workspaces for development, staging and production therefore reuse the same configuration files while keeping environments fully isolated, satisfying the stated constraint.
Run Triggers
In HCP Terraform, you want to allow team members to see runs but prevent them from approving plans. Which team permission set should you assign?
Write
Admin
Read
Read permissions grant visibility into workspaces and runs without any write or approval capability, so members can inspect run status and logs while being blocked from approving plans. This satisfies both constraints in the stem: view runs, deny approvals. Approval rights require the Write permission set, which Read deliberately excludes.
Cost Estimation
You are managing state in a multi-region deployment. You need to ensure that simultaneous terraform apply operations do not corrupt the state file. Which backend configuration parameter primarily enables this functionality?
workspace_key_prefix
kms_key_id
acl
dynamodb_table
The `dynamodb_table` parameter enables state locking by writing a lock item to a DynamoDB table before any apply begins, so a second concurrent `terraform apply` fails rather than corrupting the shared state file. This directly satisfies the stem's requirement that simultaneous operations across regions cannot overwrite each other's state.
Want more Collaborative Workflows practice?
Practice this domainYou are configuring RBAC in HCP Terraform. A user needs to trigger runs and view plan logs but should not be allowed to modify workspace variables. Which permission set is appropriate?
Grant Admin access.
Grant 'Read' and 'Queue Plan' permissions.
Granting Read plus Queue Plan satisfies the least-privilege requirement: Read exposes plan logs and workspace state, while Queue Plan permits triggering runs. Neither permission includes the variables:write capability, so the user cannot modify workspace variables. This precisely matches the stem's constraint of triggering runs and viewing logs without variable edit rights.
Grant 'Manage Variables' permission.
Grant 'Write' permission to the workspace.
Which of the following is a primary benefit of using a Private Module Registry?
It encrypts all Terraform state files.
It allows central management and version control of reusable modules.
A Private Module Registry stores modules within your own organisation, giving centralised publishing, semantic versioning and access control. This satisfies the need for central management and version control of reusable modules, unlike the public registry where you cannot govern or curate shared code.
It forces all workspaces to use the same module versions.
It automatically generates cost estimates for all modules.
A Sentinel policy is failing on a cost estimation result. What is the most likely cause if the cost estimation feature is enabled but the policy still fails?
The cost estimation provider is not configured for AWS.
The workspace does not have Sentinel enabled.
The API key for AWS is invalid.
The policy attempts to access cost data before the estimation has completed.
Cost estimation runs asynchronously after plan, so a policy evaluating cost data during the plan phase may execute before estimation finishes. The policy then reads an empty or incomplete result and fails, despite cost estimation being enabled.
When configuring team permissions, what does the 'Workspace: Settings' permission allow?
Viewing plan and apply logs only.
Triggering runs manually.
Modifying workspace settings like variable sets and execution modes.
Modifying variable sets and execution modes requires the workspace-level Settings permission, which governs configuration scoped to a single workspace rather than organisation-wide policy. This satisfies the stem's constraint by granting exactly the administrative control needed over workspace-specific variables and run behaviour, without broader access.
Deleting the workspace.
You want to enforce a policy that prevents creating AWS EC2 instances larger than 't3.medium'. Where do you configure this?
By modifying the Terraform provider source.
Inside an HCP Terraform Policy Set.
HCP Terraform policy sets enforce Sentinel or OPA policies against Terraform runs, evaluating planned EC2 instance types before apply. This blocks instance sizes exceeding t3.medium at the Terraform layer, satisfying the stem's requirement to prevent creation of larger instances.
In the Private Module Registry settings.
Within the workspace's variables.
What is the result of a 'soft-mandatory' Sentinel policy failing during a run?
The run is immediately aborted.
The policy is skipped automatically.
The run pauses and waits for an override.
Soft-mandatory sits between advisory and hard-mandatory on the enforcement scale: failure blocks the run but permits a privileged user to override, resuming it. Hard-mandatory cannot be overridden, and advisory only logs, so pausing for override matches the stem.
The run completes but triggers an alert.
Want more HCP Terraform Governance practice?
Practice this domainWhen using 'create_before_destroy', what is a common side effect that may cause the plan to fail?
Resource naming collisions.
Creating the replacement before destroying the original means both exist simultaneously, so fixed names, unique DNS labels or static identifiers clash. The provider rejects the duplicate, causing the plan or apply to fail until the name is parameterised or the old resource is destroyed first.
Terraform will delete the state file.
Provider credentials will expire.
All other resources will be destroyed.
You are managing a production database instance. You want to ensure that if a developer accidentally removes the resource block from the Terraform configuration, Terraform will refuse to destroy the database. How do you implement this?
Set prevent_destroy = true in the lifecycle block.
Setting `prevent_destroy = true` in the resource's `lifecycle` block makes Terraform reject any plan that would destroy the database, including removal of its resource block. This directly satisfies the stem's requirement that Terraform refuse destruction after an accidental configuration deletion, failing the apply with an error rather than deleting the instance.
Set create_before_destroy = false.
Use the ignore_changes meta-argument for the lifecycle block.
Configure a provider-level block to disable deletions.
Which command is used to move a resource from one state file to another, commonly used when refactoring modules?
terraform migrate
terraform plan -refactor
terraform refresh
terraform state mv
terraform state mv relocates a resource entry between state files or addresses, updating the state to match refactored configuration without destroying or recreating infrastructure. This satisfies the module-refactoring scenario by preserving existing resources while their configuration addresses change.
A resource has an attribute 'tags' that is managed by an external script. You want Terraform to ignore any changes made to 'tags' after the initial creation. How should you configure the 'lifecycle' block?
ignore_changes = [tags]
ignore_changes with the tags attribute instructs Terraform to disregard drift in that attribute after creation, so external script modifications no longer appear as diffs. This satisfies the requirement to leave post-creation tag changes untouched during planning and apply.
lifecycle { tags = ignore }
prevent_destroy = [tags]
ignore_changes = [all]
You have defined a resource and set 'prevent_destroy = true'. If you perform a 'terraform destroy', what will happen?
Terraform will destroy all resources except the one with the rule.
Terraform will ignore the rule and destroy the resource anyway.
Terraform will return an error and abort the destroy operation.
Terraform's lifecycle `prevent_destroy` meta-argument causes the plan phase to fail whenever a destroy action targets that resource, so `terraform destroy` errors out and aborts before removing anything. This satisfies the stem's protection requirement, halting the entire operation rather than skipping the resource silently.
Terraform will prompt for confirmation twice.
You want to remove a resource from Terraform management without destroying the actual AWS resource. Which command accomplishes this?
terraform destroy -target
terraform untrack
terraform apply -ignore
terraform state rm
terraform state rm deletes the resource's entry from the state file only, leaving the real AWS infrastructure untouched. Subsequent plans no longer track it, which matches the stem's requirement to remove it from management without destroying it.
Want more Resource Lifecycle Management practice?
Practice this domainWhat is the purpose of the 'terraform providers lock' command?
To secure the provider versions and checksums.
The command writes provider checksums into the dependency lock file for multiple platforms, securing the exact provider versions and their hashes. This satisfies the requirement to verify provider integrity across platforms, preventing tampering or unexpected version drift during init.
To encrypt the state file.
To prevent others from running init.
To download all providers.
You are creating a custom provider. What is the standard language used to write Terraform providers?
Python
Ruby
HCL
Go
Terraform providers are written in Go, using the Terraform Plugin SDK or Plugin Framework. This satisfies the stem's requirement for the standard language: HashiCorp builds and distributes all official providers in Go, and the plugin protocol's libraries are Go-first, making it the only supported choice for custom provider development.
You need to manage resources in two different AWS regions using the same provider configuration. How do you achieve this?
Define the region twice in a single provider block.
Define two separate aws providers in the same file without aliases.
Create two separate Terraform projects.
Use an alias in the provider block and reference it in the resource using the provider meta-argument.
Provider aliases create distinct configurations within one provider block, each pinned to a different region. Referencing the alias via the provider meta-argument on a resource directs that resource to the aliased instance, satisfying the requirement to manage two regions from a single configuration.
If you want to use a provider that is not published in the Terraform Registry, how do you install it?
Use a filesystem mirror in the .terraformrc file.
A filesystem mirror lets Terraform install a provider from a local directory instead of the public Terraform Registry, satisfying the constraint that the provider is unpublished. The .terraformrc provider_installation block redirects installation to that mirror, so no registry lookup occurs.
You cannot use private providers.
Rename the file to provider.tf.
Copy it to the root of the project.
A team wants to ensure their Terraform configuration uses a specific major version of the AWS provider to prevent breaking changes. Which block should they use?
terraform { required_providers { aws = { source = "hashicorp/aws", version = "~> 4.0" } } }
The `~>` pessimistic constraint operator permits patch and minor upgrades within major version 4, blocking the breaking changes that version 5 would introduce. Placing it inside `required_providers` within the `terraform` block satisfies the stem's requirement to pin a specific major version of the AWS provider.
provider "aws" { version = "~> 4.0" }
terraform { version = "~> 4.0" }
provider_version = "4.0"
Where are providers physically stored by default when running 'terraform init'?
The root module directory
~/.terraformrc
.terraform/providers/
Terraform caches downloaded provider plugins in the .terraform/providers/ directory within the working directory, so subsequent runs reuse them without re-downloading. This satisfies the default storage location constraint, as init installs providers there unless a plugin cache directory is configured.
/usr/local/bin/terraform
Want more Provider Management practice?
Practice this domainThe vendor does not publish an exact question count for the AWS provider. Always confirm current details on the vendor's official exam page.
Scenario-based questions covering exam objectives with detailed answer explanations.
The exam covers 6 domains: Dynamic HCL Configuration, Terraform Modules, Collaborative Workflows, HCP Terraform Governance, Resource Lifecycle Management, Provider Management. Questions are weighted by domain — higher-weight domains appear more on your actual exam.
No. These are original exam-style practice questions written against the official HashiCorp AWS provider exam objectives. They are not copied from the real exam. Courseiva focuses on genuine understanding, not memorisation of braindumps.
Courseiva tracks your accuracy per domain and routes you toward weak areas automatically. Free, no account required.