Terraform Associate · 16% of the exam

Configuration, HCL, and Functions: free practice questions

5 sample questions from our 40-question bank for this domain — answers and explanations included. These are the same scenario-based style as the real HashiCorp exam.

1. A developer writes the following locals block: ```hcl locals { env = "prod" prefix = "myapp" bucket_name = format("%s-%s-%s", local.prefix, local.env, "assets") } ``` What will `local.bucket_name` evaluate to?

  • A. "myapp-prod-assets"✓ Correct
  • B. "myapp_prod_assets"
  • C. "%s-%s-%s"
  • D. An error, because `local` values cannot reference other `local` values inside the same block.
Explanation

Option A is correct: `format("%s-%s-%s", "myapp", "prod", "assets")` substitutes each `%s` placeholder with the corresponding argument separated by `-`, producing `"myapp-prod-assets"`. Option B is wrong: the format string uses `-` as a separator, not `_`. The result uses dashes. Option C is wrong: `%s` placeholders in `format()` are replaced with the provided arguments; the format string itself is never returned as-is. Option D is wrong: Terraform fully supports cross-referencing local values within the same module (even within the same `locals` block). Terraform resolves them in dependency order.

2. A developer writes the following Terraform configuration to build a flattened list of objects from a nested map, intending to create one `aws_route53_record` per entry: ```hcl variable "dns_zones" { default = { "example.com" = ["www", "api"] "test.com" = ["app"] } } locals { dns_records = flatten([ for zone, subdomains in var.dns_zones : [ for sub in subdomains : { zone = zone subdomain = sub } ] ]) } resource "aws_route53_record" "records" { for_each = { for r in local.dns_records : "${r.zone}-${r.subdomain}" => r } zone_id = "Z1234567890" name = "${each.value.subdomain}.${each.value.zone}" type = "A" ttl = 300 records = ["1.2.3.4"] } ``` How many `aws_route53_record` resources will Terraform plan to create, and what will their `for_each` keys be?

  • A. Two resources with keys `"example.com"` and `"test.com"` — one per zone.
  • B. Three resources with keys `"example.com-www"`, `"example.com-api"`, and `"test.com-app"`.✓ Correct
  • C. Three resources, but the keys will be `"www"`, `"api"`, and `"app"` because `for_each` strips the zone prefix.
  • D. An error, because `flatten()` cannot process a list of objects — it only works with lists of strings.
Explanation

**Three resources with keys `"example.com-www"`, `"example.com-api"`, and `"test.com-app"`** is correct. The nested `for` expressions inside `flatten()` produce three objects: `{zone="example.com", subdomain="www"}`, `{zone="example.com", subdomain="api"}`, and `{zone="test.com", subdomain="app"}`. The subsequent `for` expression converts this list to a map keyed by `"${r.zone}-${r.subdomain}"`, yielding three distinct keys. **Two resources per zone** is incorrect because the inner loop iterates over subdomains. **Stripping the zone prefix** is incorrect; the key expression explicitly includes both zone and subdomain. **An error from `flatten()`** is incorrect; `flatten()` works on lists of any type, including lists of objects.

3. A platform engineer writes the following dynamic block inside an `aws_security_group` resource to generate ingress rules from a variable: ```hcl variable "ingress_rules" { type = list(object({ port = number protocol = string cidr_blocks = list(string) })) } resource "aws_security_group" "app" { name = "app-sg" dynamic "ingress" { for_each = var.ingress_rules content { from_port = ingress.value.port to_port = ingress.value.port protocol = ingress.value.protocol cidr_blocks = ingress.value.cidr_blocks } } } ``` The developer passes the following value for `ingress_rules`: ```hcl ingress_rules = [ { port = 443, protocol = "tcp", cidr_blocks = ["0.0.0.0/0"] }, { port = 22, protocol = "tcp", cidr_blocks = ["10.0.0.0/8"] } ] ``` How many `ingress` blocks will be generated in the resulting security group resource?

  • A. 0, because dynamic blocks require a map, not a list, for for_each
  • B. 1, because dynamic blocks only generate a single merged block
  • C. 2, one for each element in the ingress_rules list✓ Correct
  • D. An error occurs because the iterator label must match the resource block type exactly
Explanation

**2 ingress blocks** is correct. The `dynamic` block iterates over `var.ingress_rules`, which has two elements, producing one `ingress` block per element. **0 / requires a map** is incorrect — `dynamic` blocks accept both lists and maps for `for_each`. **1 merged block** is incorrect — each iteration produces a distinct, independent nested block. **Error about iterator label** is incorrect — the iterator label in a `dynamic` block (here `ingress`) is a user-chosen reference name, not required to match anything other than itself in the `content` block; it does not need to exactly mirror internal resource block names beyond the `dynamic "ingress"` label matching the nested block type.

4. 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.

5. A Terraform developer declares the following variable: ```hcl 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. tolist(var.region_codes)
  • B. toset(var.region_codes)✓ Correct
  • C. distinct(var.region_codes)
  • D. tomap(var.region_codes)
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.

35 more questions in this domain

Practice the full bank with instant grading, flashcards, and a timed mock exam.

Start practicing free