Conditional resource creation in Terraform for_each block

For example, we have Terraform code like bellow:

### VPC ####
resource "aws_vpc" "vpc" 
  for_each             = var.vpcs
  cidr_block           = each.value.cidr_block
  enable_dns_hostname  = each.value.enable_dns_hostnames
  enable_dns_support   = each.value.enable_dns_support
  tag = {
    Name = each.value.name
  }
}

#####################################
# Internet Gateway Settings
#####################################
resource "aws_internet_gateway" "igw" {
  for_each = var.vpcs
  vpc_id = aws_vpc.vpc[each.key].id
  tags = {
    Name = each.value.igw_name
  }
}

Now you want your “igw” resource is only created when you pass a condition. What you should do now?

\=> Solution:

You should use conditions with for_each in the block code to create “igw” resource as following:”

#####################################
# Internet Gateway Settings
#####################################

resource "aws_internet_gateway" "igw" {
  for_each = {
    for key, value in var.vpcs: key => value if value.igw_created == "true"
  }
  vpc_id = aws_vpc.vpc[each.key].id
  tags = {
    Name = "${var.app_name}-${var.env_name}-igw"
  }
}

variables.tf:

variable "vpcs" {
  default = []
}

terraform.tfvars

vpcs = {
  vpc_001 = {
    cidr_block = "10.82.0.0/16"
    enable_dns_hostnames = "true"
    enable_dns_support = "true"
    name = "vpc_001"
    igw_created = "true"
    igw_name = "igw_name-1"
  }

  vpc_002 = {
    cidr_block = "10.83.0.0/16"
    enable_dns_hostnames = "true"
    enable_dns_support = "false"
    name = "vpc_002"
    igw_created = "false"
    igw_name = "igw-name-2"
  }

  vpc_003 = {
    cidr_block = "10.84.0.0/16"
    enable_dns_hostnames = "true"
    enable_dns_support = "true"
    name = "vpc_003"
    igw_created = "true"
    igw_name = "igw-name-3"
  }
}

Terraform apply:

PS D:\infra-as-code\learning> terraform apply --auto-approve

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # aws_internet_gateway.igw["vpc_001"] will be created
  + resource "aws_internet_gateway" "igw" {
      + arn      = (known after apply)
      + id       = (known after apply)
      + owner_id = (known after apply)
      + tags     = {
          + "Name" = "igw_name-1"
        }
      + tags_all = {
          + "Name" = "igw_name-1"
        }
      + vpc_id   = (known after apply)
    }

  # aws_internet_gateway.igw["vpc_003"] will be created
  + resource "aws_internet_gateway" "igw" {
      + arn      = (known after apply)
      + id       = (known after apply)
      + owner_id = (known after apply)
      + tags     = {
          + "Name" = "igw-name-3"
        }
      + tags_all = {
          + "Name" = "igw-name-3"
        }
      + vpc_id   = (known after apply)
    }

  # aws_vpc.vpc["vpc_001"] will be created
  + resource "aws_vpc" "vpc" {
      + arn                                  = (known after apply)
      + cidr_block                           = "10.82.0.0/16"
      + default_network_acl_id               = (known after apply)
      + default_route_table_id               = (known after apply)
      + default_security_group_id            = (known after apply)
      + dhcp_options_id                      = (known after apply)
      + enable_classiclink                   = (known after apply)
      + enable_classiclink_dns_support       = (known after apply)
      + enable_dns_hostnames                 = true
      + enable_dns_support                   = true
      + id                                   = (known after apply)
      + instance_tenancy                     = "default"
      + ipv6_association_id                  = (known after apply)
      + ipv6_cidr_block                      = (known after apply)
      + ipv6_cidr_block_network_border_group = (known after apply)
      + main_route_table_id                  = (known after apply)
      + owner_id                             = (known after apply)
      + tags                                 = {
          + "Name" = "vpc_001"
        }
      + tags_all                             = {
          + "Name" = "vpc_001"
        }
    }

  # aws_vpc.vpc["vpc_002"] will be created
  + resource "aws_vpc" "vpc" {
      + arn                                  = (known after apply)
      + cidr_block                           = "10.83.0.0/16"
      + default_network_acl_id               = (known after apply)
      + default_route_table_id               = (known after apply)
      + default_security_group_id            = (known after apply)
      + dhcp_options_id                      = (known after apply)
      + enable_classiclink                   = (known after apply)
      + enable_classiclink_dns_support       = (known after apply)
      + enable_dns_hostnames                 = true
      + enable_dns_support                   = false
      + id                                   = (known after apply)
      + instance_tenancy                     = "default"
      + ipv6_association_id                  = (known after apply)
      + ipv6_cidr_block                      = (known after apply)
      + ipv6_cidr_block_network_border_group = (known after apply)
      + main_route_table_id                  = (known after apply)
      + owner_id                             = (known after apply)
      + tags                                 = {
          + "Name" = "vpc_002"
        }
      + tags_all                             = {
          + "Name" = "vpc_002"
        }
    }

  # aws_vpc.vpc["vpc_003"] will be created
  + resource "aws_vpc" "vpc" {
      + arn                                  = (known after apply)
      + cidr_block                           = "10.84.0.0/16"
      + default_network_acl_id               = (known after apply)
      + default_route_table_id               = (known after apply)
      + default_security_group_id            = (known after apply)
      + dhcp_options_id                      = (known after apply)
      + enable_classiclink                   = (known after apply)
      + enable_classiclink_dns_support       = (known after apply)
      + enable_dns_hostnames                 = true
      + enable_dns_support                   = true
      + id                                   = (known after apply)
      + instance_tenancy                     = "default"
      + ipv6_association_id                  = (known after apply)
      + ipv6_cidr_block                      = (known after apply)
      + ipv6_cidr_block_network_border_group = (known after apply)
      + main_route_table_id                  = (known after apply)
      + owner_id                             = (known after apply)
      + tags                                 = {
          + "Name" = "vpc_003"
        }
      + tags_all                             = {
          + "Name" = "vpc_003"
        }
    }

Plan: 5 to add, 0 to change, 0 to destroy.
aws_vpc.vpc["vpc_003"]: Creating...
aws_vpc.vpc["vpc_002"]: Creating...
aws_vpc.vpc["vpc_001"]: Creating...
aws_vpc.vpc["vpc_002"]: Still creating... [10s elapsed]
aws_vpc.vpc["vpc_003"]: Still creating... [10s elapsed]
aws_vpc.vpc["vpc_001"]: Still creating... [10s elapsed]
aws_vpc.vpc["vpc_003"]: Creation complete after 16s [id=vpc-0a14cac4154954b9c]
aws_vpc.vpc["vpc_001"]: Creation complete after 18s [id=vpc-01a80c067fac86d35]
aws_vpc.vpc["vpc_002"]: Still creating... [20s elapsed]
aws_vpc.vpc["vpc_002"]: Creation complete after 27s [id=vpc-096a193439c5b5305]
aws_internet_gateway.igw["vpc_003"]: Creating...
aws_internet_gateway.igw["vpc_001"]: Creating...
aws_internet_gateway.igw["vpc_003"]: Creation complete after 1s [id=igw-0238cd7c78cc107eb]
aws_internet_gateway.igw["vpc_001"]: Creation complete after 2s [id=igw-040131b45dd87f7e5]

Apply complete! Resources: 5 added, 0 changed, 0 destroyed.

Note: You can also write for_each part of your Terraform code as below:

### VPC ####
resource "aws_vpc" "vpc" 
  for_each             = var.vpcs
  cidr_block           = each.value.cidr_block
  enable_dns_hostname  = each.value.enable_dns_hostnames
  enable_dns_support   = each.value.enable_dns_support
  tag = {
    Name = "${var.app_name}-${var.env_name}-${each.value.name_vpc}"
  }
}

#####################################
# Internet Gateway Settings
#####################################
resource "aws_internet_gateway" "igw" {
  for_each = var.igws
  vpc_id = aws_vpc.vpc[each.key].id
  tags = {
    Name = "${var.app_name}-${var.env_name}-${each.value.name_igw}"
  }
}

However, please note that sometimes, you should not use for_each. Why?

\=> Because if there are so many VPC’s dependent resources, it means all of those resource have to be in for_each loops. And if you change one thing -> So many other affected. In this case, you should consider refactor your code and use Terraform modules.