Skip to content

Cannot apply multiple module instances at once when depending on to-be-created resource #25

@TheKangaroo

Description

@TheKangaroo

I'm attempting to deploy multiple inspection VPCs across various regions using the following code. However, the apply fails when I reference resources that need to be created in the same Terraform run as the inspection VPC/firewall itself. I can't even deploy the dependencies using --target apply. The only workaround I've found is:

  1. Comment out the module
  2. Use --target apply for the dependencies
  3. Uncomment the module
  4. Apply
locals {
  inspection_vpcs = {
    frankfurt = {
      region = "eu-central-1"
	  range = "10.0.0.0/24"
    }
    paris = {
      region = "eu-west-3"
	  range = "10.0.1.0/24"
    }
  }
}

module "inspection_vpc" {
  for_each = local.inspection_vpcs
  providers = {
    aws = aws.by_region[each.value.region]
  }

  source  = "aws-ia/cloudwan/aws"
  version = "3.2.0"

  core_network_arn = module.cloudwan.core_network.arn

  aws_network_firewall = {
    inspection-east-west = {
      name        = "inspection"
      description = "AWS Network Firewall - East/West"
      policy_arn  = aws_networkfirewall_firewall_policy.inspection[each.key].arn # <- this does not work
    }
  }
  central_vpcs = {
    inspection-east-west = {
      type       = "inspection"
      cidr_block = each.value.range                       # same problem when referenced from a resource
      az_count   = 3

      subnets = {
        endpoints = { netmask = 28 }
        core_network = {
          netmask = 28
          tags    = { connect = "inspection" }
        }
      }
    }
  }
}

resource "aws_networkfirewall_firewall_policy" "inspection" {
  for_each = local.inspection_vpcs
  provider = aws.by_region[each.value.region]

  name = "policy"

  firewall_policy {
    stateless_default_actions          = ["aws:pass"]
    stateless_fragment_default_actions = ["aws:pass"]
  }
}

# provider config
locals {
  provider_regions = toset([
    "eu-central-1",
    "eu-west-3",
  ])
}

provider "aws" {
  alias    = "by_region"
  for_each = local.provider_regions
  region   = each.key
  assume_role {
    role_arn = "arn:aws:iam::${local.aws_account_id}:role/AWSControlTowerExecution"
  }
}

The error is the following:

│ Error: Invalid for_each argument
│
│   on .terraform/modules/inspection_vpc/main.tf line 109, in module "network_firewall":
│  109:   for_each = {
│  110:     for k, v in try(var.central_vpcs, {}) : k => v
│  111:     if contains(["inspection", "egress_with_inspection", "ingress_with_inspection"], v.type) && contains(keys(var.aws_network_firewall), k)
│  112:   }
│     ├────────────────
│     │ var.aws_network_firewall is object with 1 attribute "inspection-east-west"
│     │ var.central_vpcs is object with 1 attribute "inspection-east-west"
│
│ The "for_each" map includes keys derived from resource attributes that cannot be determined until apply, and so OpenTofu cannot determine the full set of keys that will identify the instances of this resource.
│
│ When working with unknown values in for_each, it's better to define the map keys statically in your configuration and place apply-time results only in the map values.
│
│ Alternatively, you could use the -target planning option to first apply only the resources that the for_each value depends on, and then apply a second time to fully converge.

I use opentofu BTW.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions