4 min read | by Jordi Prats
Let's imagine we want to create a security group with the following ingress rules:
ingress_rules = [
{
protocol = "tcp"
cidr_blocks = [ "1.1.1.1/32", "2.2.2.2/32" ]
},
{
protocol = "tcp"
cidr_blocks = [ "1.2.3.4/32" ]
}
]
For each of the following ports:
services = ["80", "443", "8080"]
We can use the terraform function setproduct() to calculate all the combinations of elements from the given sets. That's also called the Cartesian product. For this example it's going to be 2x3.
We can use the following code that loops using for_each on the resulting values from using setproduct on both lists:
dynamic "ingress" {
for_each = setproduct(var.ingress_rules, var.services)
content {
description = "allow ${ingress.value[1]}"
from_port = ingress.value[1]
to_port = ingress.value[1]
protocol = ingress.value[0]["protocol"]
cidr_blocks = ingress.value[0]["cidr_blocks"]
}
}
Its going to create 6 rules, we can test it using terraform plan:
$ terraform plan
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_security_group.demo_sg will be created
+ resource "aws_security_group" "demo_sg" {
+ arn = (known after apply)
+ description = "Managed by Terraform"
+ egress = (known after apply)
+ id = (known after apply)
+ ingress = [
+ {
+ cidr_blocks = [
+ "1.1.1.1/32",
+ "2.2.2.2/32",
]
+ description = "allow 443"
+ from_port = 443
+ ipv6_cidr_blocks = []
+ prefix_list_ids = []
+ protocol = "tcp"
+ security_groups = []
+ self = false
+ to_port = 443
},
+ {
+ cidr_blocks = [
+ "1.1.1.1/32",
+ "2.2.2.2/32",
]
+ description = "allow 80"
+ from_port = 80
+ ipv6_cidr_blocks = []
+ prefix_list_ids = []
+ protocol = "tcp"
+ security_groups = []
+ self = false
+ to_port = 80
},
+ {
+ cidr_blocks = [
+ "1.1.1.1/32",
+ "2.2.2.2/32",
]
+ description = "allow 8080"
+ from_port = 8080
+ ipv6_cidr_blocks = []
+ prefix_list_ids = []
+ protocol = "tcp"
+ security_groups = []
+ self = false
+ to_port = 8080
},
+ {
+ cidr_blocks = [
+ "1.2.3.4/32",
]
+ description = "allow 443"
+ from_port = 443
+ ipv6_cidr_blocks = []
+ prefix_list_ids = []
+ protocol = "tcp"
+ security_groups = []
+ self = false
+ to_port = 443
},
+ {
+ cidr_blocks = [
+ "1.2.3.4/32",
]
+ description = "allow 80"
+ from_port = 80
+ ipv6_cidr_blocks = []
+ prefix_list_ids = []
+ protocol = "tcp"
+ security_groups = []
+ self = false
+ to_port = 80
},
+ {
+ cidr_blocks = [
+ "1.2.3.4/32",
]
+ description = "allow 8080"
+ from_port = 8080
+ ipv6_cidr_blocks = []
+ prefix_list_ids = []
+ protocol = "tcp"
+ security_groups = []
+ self = false
+ to_port = 8080
},
]
+ name = "demo_sg"
+ name_prefix = (known after apply)
+ owner_id = (known after apply)
+ revoke_rules_on_delete = false
+ tags_all = (known after apply)
+ vpc_id = "vpc-1a2b3c4d"
}
Plan: 1 to add, 0 to change, 0 to destroy.
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform apply" now.
You'll be able to find the the code used on this post on the following github repo:
https://github.com/pet2cattle/terraform-setproduct
Posted on 16/06/2021