HashiCorp Terraform Associate (004) · 12% practice allocation

HashiCorp 004: Terraform configuration Practice Questions

5 free sample questions from the Terraform configuration domain, with answers and explanations. The full 004 bank has 282 questions across 8 domains. Questions are scenario-based and written from the official HashiCorp exam guide.

1.

A senior engineer is writing a reusable module that accepts a variable with complex type constraints and wants to ensure that no caller accidentally passes an empty list of subnet IDs. They write:

variable "subnet_ids" {
  type        = list(string)
  description = "List of subnet IDs for the deployment"

  validation {
    condition     = length(var.subnet_ids) > 0
    error_message = "At least one subnet ID must be provided."
  }
}

variable "instance_config" {
  type = object({
    instance_type = string
    spot_price    = optional(number, null)
    ebs_optimized = optional(bool, true)
  })
}

The caller passes:

subnet_ids       = []
instance_config  = { instance_type = "t3.medium" }

Which TWO statements correctly describe the outcome of running terraform plan with this configuration?

  • A. Terraform raises a validation error on subnet_ids because the list is empty, displaying "At least one subnet ID must be provided."✓ Correct
  • B. Terraform merges the partial instance_config object with the module's local defaults automatically
  • C. Terraform raises an error because the optional() modifier is not valid inside object() type constraints
  • D. The validation block on subnet_ids is skipped because the variable has no default value
  • E. The instance_config variable is accepted, with spot_price defaulting to null and ebs_optimized defaulting to true✓ Correct
  • F. Terraform raises a type error on instance_config because spot_price and ebs_optimized are not supplied
Explanation

Validation error on subnet_ids is correct — passing an empty list [] causes length(var.subnet_ids) > 0 to evaluate to false, triggering the custom error_message. Type error on instance_config is wrong — the optional() modifier in object() type constraints (introduced in Terraform 1.3) explicitly allows callers to omit those attributes; omitting them does not cause an error. Defaults applied for instance_config is correct — optional(number, null) defaults spot_price to null and optional(bool, true) defaults ebs_optimized to true when not supplied by the caller. optional() is invalid is wrong — optional() is a fully supported built-in modifier for object type constraints since Terraform 1.3. Validation skipped without default is wrong — validation blocks run whenever a value is provided, regardless of whether the variable has a default; here a value ([]) is explicitly passed. Merges with local defaults is wrong — Terraform's optional() modifier provides per-attribute defaults at the type level; there is no automatic merging with module-level locals.

2.

A developer needs to output a sensitive database password in Terraform without exposing it in terraform plan or terraform apply console output. Which configuration correctly marks the output as sensitive?

output "db_password" {
  value = aws_db_instance.main.password
  # Which attribute goes here?
}
  • A. redact = true
  • B. encrypted = true
  • C. secret = true
  • D. sensitive = true✓ Correct
Explanation

sensitive = true is the correct Terraform output attribute that instructs Terraform to redact the value from CLI output, displaying (sensitive value) instead. secret = true is not a valid Terraform output attribute. encrypted = true is not a valid Terraform output attribute; encryption is handled by the backend, not the output block. redact = true is not a valid Terraform output attribute.

3.

Which TWO of the following statements correctly describe the behavior of dynamic blocks in Terraform?

  • A. A dynamic block can be used to generate any repeatable nested block, such as ingress rules inside an aws_security_group resource.✓ Correct
  • B. The iterator variable inside a dynamic block defaults to the label of the dynamic block itself if no iterator argument is specified.✓ Correct
  • C. Dynamic blocks can be used to generate top-level resource blocks (e.g., creating multiple resource blocks from a list).
  • D. The content block inside a dynamic block is optional and can be omitted if the nested block has no attributes.
  • E. Dynamic blocks can only iterate over lists; maps and sets are not supported as for_each values.
Explanation

Statement A is correct: dynamic blocks are specifically designed to programmatically generate repeated nested blocks (like ingress, egress, tag, etc.) within a resource or module block. Statement B is correct: by default, the iterator object inside a dynamic block shares the name of the dynamic block's label (e.g., dynamic "ingress" gives an iterator named ingress); you can override this with the iterator argument. Statement C is incorrect: dynamic blocks only work for nested blocks within a resource/data/provider; they cannot generate top-level resource blocks — that requires count or for_each on the resource itself. Statement D is incorrect: the content block is required inside every dynamic block; omitting it causes a configuration error. Statement E is incorrect: for_each inside dynamic blocks supports lists, maps, and sets.

4.

A developer writes the following Terraform configuration:

variable "enable_monitoring" {
  type    = bool
  default = false
}

resource "aws_instance" "web" {
  ami           = "ami-0abcdef1234567890"
  instance_type = var.enable_monitoring ? "t3.large" : "t3.micro"
}

The developer runs terraform apply without passing any variable values. What instance type will be used?

  • A. t3.large, because bool variables default to true
  • B. t3.micro, because the default value of enable_monitoring is false✓ Correct
  • C. An error occurs because conditional expressions require explicit variable values
  • D. t3.large, because the ternary operator always evaluates the first branch first
Explanation

t3.micro is correct. The variable enable_monitoring defaults to false, so the conditional expression false ? "t3.large" : "t3.micro" evaluates to "t3.micro". t3.large (first option) is wrong because bool variables do not default to true unless explicitly set. An error occurs is wrong — Terraform's ternary/conditional expression works perfectly with default variable values; no explicit value is required. t3.large (last option) is wrong — the ternary operator evaluates the condition, not just the first branch unconditionally.

5.

A Terraform developer declares the following variable:

variable "region_codes" {
  type    = list(string)
  default = ["us-east-1", "us-west-2", "eu-west-1"]
}

Which built-in function would convert this variable's value into a collection that guarantees uniqueness and is most appropriate to pass to a for_each meta-argument?

  • A. tomap(var.region_codes)
  • B. distinct(var.region_codes)
  • C. tolist(var.region_codes)
  • D. toset(var.region_codes)✓ Correct
Explanation

toset() converts a list to a set, which enforces uniqueness and is the correct type required by for_each when iterating over a flat collection of strings. tolist() keeps the list type, and for_each does not accept plain lists — it requires a set or map, so this would cause a type error. distinct() also removes duplicates but returns a list, not a set, so it still cannot be passed directly to for_each without further conversion. tomap() requires a list of two-element tuples or similar structure and cannot be applied to a flat list of strings, causing a runtime error.

Test yourself across every 004 domain

The free 004 practice test mixes about 20 questions weighted like the exam. The full 282-question bank adds instant grading, flashcards and a timed mock exam.

Study this domain

Terraform configuration study guide (004) →

Other 004 domains

← All HashiCorp Terraform Associate study resources