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"
}
}
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.