Skip to content

002 · Domain 1: Scalable Terraform Configuration Design · 20% of the exam

Task 1.4: Trace dynamic resources created with for_each

What for_each creates and how to read it back: instance keys from maps and sets, each.key and each.value, the addresses that terraform state list and state show print, and values that are not known until apply.

Study it

  • for_each instances: keys, each.value and the addresses state prints

    Lesson coming

Sample questions

Try each one before opening the answer. Every option is explained, with the HashiCorp documentation page that proves it.

Question 1 · choose 1

A new environment is applied from scratch with: variable "public_subnets" { type = map(string) # zone => CIDR } resource "aws_subnet" "public" { for_each = var.public_subnets cidr_block = each.value # ... } resource "aws_nat_gateway" "this" { for_each = toset([for s in aws_subnet.public : s.id]) subnet_id = each.value } The plan fails with "Invalid for_each argument". The fix must work in a single plan and apply for every new environment. What should the team do?

  1. ARun a targeted apply of aws_subnet.public first, then apply the rest of the configuration
  2. BAdd depends_on = [aws_subnet.public] to the NAT gateways to make each subnet_id known in time
  3. CWrap the expression in tomap() to give for_each a map like var.public_subnets instead of a set
  4. DUse for_each = var.public_subnets and set subnet_id = aws_subnet.public[each.key].id instead
Show the answer and why
  • ARun a targeted apply of aws_subnet.public first, then apply the rest of the configuration

    Incorrect

    It works once, but every new environment then needs two runs, which the requirement rules out.

  • BAdd depends_on = [aws_subnet.public] to the NAT gateways to make each subnet_id known in time

    Incorrect

    depends_on orders operations; it cannot make an ID that the cloud assigns at creation known during planning.

  • CWrap the expression in tomap() to give for_each a map like var.public_subnets instead of a set

    Incorrect

    The problem is that the values used as keys are unknown, not the collection type; converting does not make them known.

  • DUse for_each = var.public_subnets and set subnet_id = aws_subnet.public[each.key].id instead

    Correct

    The zone names are known at plan time, so they can be instance keys, and the unknown subnet ID is only an argument value, which may be unknown.

for_each keys must be known before any remote operation. Subnet IDs are assigned at creation, so keying by them fails on a first apply; keying by the zone names from the variable and referencing the ID as a value works in one run.

Question 2 · choose 1

A module receives var.ports = [80, 443] with type list(number) and sets for_each = toset(var.ports) on a security group rule. The plan rejects the for_each value. Which for_each works?

  1. Afor_each = var.ports
  2. Bfor_each = toset([for p in var.ports : tostring(p)])
  3. Cfor_each = length(var.ports)
  4. Dfor_each = toset(var.ports), with the variable type changed to list(any)
Show the answer and why
  • Afor_each = var.ports

    Incorrect

    for_each accepts a map or a set of strings, not a list.

  • Bfor_each = toset([for p in var.ports : tostring(p)])

    Correct

    Converting each number to a string gives a set of strings, with instance keys "80" and "443".

  • Cfor_each = length(var.ports)

    Incorrect

    A number is a count; for_each needs a map or a set of strings.

  • Dfor_each = toset(var.ports), with the variable type changed to list(any)

    Incorrect

    The elements are still numbers, so toset still returns a set of numbers rather than a set of strings.

Derive string keys for for_each, and convert back with tonumber() wherever a resource argument needs the number, such as from_port = tonumber(each.key).

Question 3 · choose 1

aws_lb.app uses for_each over three environments. An author writes output "dns" { for_each = aws_lb.app, value = each.value.dns_name }, and terraform validate rejects the output. What is the reason?

  1. Afor_each is not supported in output blocks
  2. Bfor_each in outputs needs a set, not map
  3. CThe value must use each.key, not each.value
  4. DThe output first needs depends_on = [aws_lb.app]
Show the answer and why
  • Afor_each is not supported in output blocks

    Correct

    The for_each reference lists data, ephemeral, module and resource blocks as the configuration blocks that support it; output blocks are not among them.

  • Bfor_each in outputs needs a set, not map

    Incorrect

    Outputs do not take for_each at all, whatever the collection type.

  • CThe value must use each.key, not each.value

    Incorrect

    The problem is the for_each argument itself, which no output block supports.

  • DThe output first needs depends_on = [aws_lb.app]

    Incorrect

    No other argument makes for_each valid in an output block.

A resource with for_each already appears as a map of instance objects in expressions, so one output can expose the whole resource or a single value computed from it.

Question 4 · choose 1

A module uses for_each = var.db_users, where db_users is a map(string) variable declared with sensitive = true. What happens at plan?

  1. ATerraform hides the instance keys in the plan output
  2. BTerraform removes the sensitive marking from the for_each keys automatically
  3. CAn error: sensitive values are not allowed in for_each
  4. DThe plan succeeds, but the instances get numeric indexes instead of keys
Show the answer and why
  • ATerraform hides the instance keys in the plan output

    Incorrect

    Terraform does not redact for_each keys; it refuses the sensitive value instead.

  • BTerraform removes the sensitive marking from the for_each keys automatically

    Incorrect

    Terraform never drops a sensitive marking on its own.

  • CAn error: sensitive values are not allowed in for_each

    Correct

    Terraform uses the for_each value to identify instances and always discloses it in UI output, so it rejects sensitive values.

  • DThe plan succeeds, but the instances get numeric indexes instead of keys

    Incorrect

    for_each instances are always identified by key; Terraform does not fall back to indexes.

Derive non-sensitive keys, for example toset([for k, v in local.map : k]) when only the values are sensitive, and keep secrets in the values.

Question 5 · choose 1

Three databases come from resource "aws_db_instance" "db" with for_each = local.environments. Each must get its own generated password through the write-only password_wo argument (other arguments omitted), and no password may be stored in state or plan files. Which configuration meets both rules?

  1. AOne ephemeral "random_password" "db" without for_each, shared through password_wo = ephemeral.random_password.db.result
  2. Bresource "random_password" "db" with for_each, and password_wo = random_password.db[each.key].result
  3. Cephemeral "random_password" "db" with for_each, and password_wo = ephemeral.random_password.db.result
  4. Dephemeral "random_password" "db" with for_each, and password_wo = ephemeral.random_password.db[each.key].result
Show the answer and why
  • AOne ephemeral "random_password" "db" without for_each, shared through password_wo = ephemeral.random_password.db.result

    Incorrect

    One ephemeral resource instance gives all three databases the same password, which breaks the first rule.

  • Bresource "random_password" "db" with for_each, and password_wo = random_password.db[each.key].result

    Incorrect

    A managed random_password resource keeps its result in state, which breaks the second rule.

  • Cephemeral "random_password" "db" with for_each, and password_wo = ephemeral.random_password.db.result

    Incorrect

    With for_each the ephemeral block has one instance per key, so the reference needs the instance key.

  • Dephemeral "random_password" "db" with for_each, and password_wo = ephemeral.random_password.db[each.key].result

    Correct

    ephemeral blocks support for_each, each database reads the instance with its own key, and Terraform stores neither ephemeral values nor write-only arguments.

Ephemeral resources use the same instance addressing as managed resources: ephemeral.<TYPE>.<NAME>[<KEY>]. Write-only arguments then pass each value to the provider without persisting it.

Practice domain 1 →Practice all domains →