I am trying to build a dynamic aws_security_group Terraform module. This module will take in a few variables:
variable "region" {
default = "us-east-1"
type = string
}
variable "security_group_list" {
description = "List of security groups to be made"
}
The variable "security_group_list" takes in a yaml file that has been decoded by the following:
module "test-security-group" {
source = "../"
security_group_list = yamldecode(file("${path.module}/test.yaml"))
region = "us-west-1"
}
The YAML file that is being decode is currently structured like this:
test-security-group:
ingress_rules:
description: "Test description"
is_self_source: "false"
from_port: 80
to_port: 80
protocol: "tcp"
cidr_blocks: ["0.0.0.0/0"]
ingress_rules:
description: "Test description 2"
is_self_source: "false"
from_port: 443
to_port: 443
protocol: "tcp"
cidr_blocks: ["0.0.0.0/0"]
ingress_rules:
description: "Test description 3"
is_self_source: "false"
from_port: 8080
to_port: 8080
protocol: "tcp"
cidr_blocks: ["0.0.0.0/0"]
egress_rules:
description: "Test description 4"
is_self_source: "false"
from_port: 80
to_port: 80
protocol: "tcp"
cidr_blocks: ["0.0.0.0/0"]
The code in this module is:
#-------------------------------------------
#Dynamic Security Group
#-------------------------------------------
resource "aws_security_group" "security_group" {
for_each = var.security_group_list
name = each.key
dynamic "ingress" {
for_each = each.value.ingress_rules[*]
content {
description = each.value.ingress_rules.description
from_port = each.value.ingress_rules.from_port
to_port = each.value.ingress_rules.to_port
protocol = each.value.ingress_rules.protocol
cidr_blocks = each.value.ingress_rules.cidr_blocks
self = each.value.ingress_rules.is_self_source
}
}
dynamic "egress" {
for_each = each.value.egress_rules[*]
content {
description = each.value.egress_rules.description
from_port = each.value.egress_rules.from_port
to_port = each.value.egress_rules.to_port
protocol = each.value.egress_rules.protocol
cidr_blocks = each.value.egress_rules.cidr_blocks
self = each.value.egress_rules.is_self_source
}
}
}
I am able to successfully run terraform validate and terraform apply. When I do so I get the following output from the CLI:
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# module.test-security-group.aws_security_group.security_group["test-security-group"] will be created
+ resource "aws_security_group" "security_group" {
+ arn = (known after apply)
+ description = "Managed by Terraform"
+ egress = [
+ {
+ cidr_blocks = [
+ "0.0.0.0/0",
]
+ description = "Test description 4"
+ from_port = 80
+ ipv6_cidr_blocks = []
+ prefix_list_ids = []
+ protocol = "tcp"
+ security_groups = []
+ self = false
+ to_port = 80
},
]
+ id = (known after apply)
+ ingress = [
+ {
+ cidr_blocks = [
+ "0.0.0.0/0",
]
+ description = "Test description 3"
+ from_port = 8080
+ ipv6_cidr_blocks = []
+ prefix_list_ids = []
+ protocol = "tcp"
+ security_groups = []
+ self = false
+ to_port = 8080
},
]
+ name = "test-security-group"
+ name_prefix = (known after apply)
+ owner_id = (known after apply)
+ revoke_rules_on_delete = false
+ vpc_id = (known after apply)
}
Plan: 1 to add, 0 to change, 0 to destroy.
The problem that I am having is that this code keeps skipping over the other "ingress_rules" that are specified in the YAML file. It seems to always only apply the last "ingress_rule" in the list. I have tried restrucuting the YAML file in multiple ways including making it a tuple. I am new to for_each loops in Terraform and new to YAML files. If someone can help me figure out why this code is skipping over the other "ingress_rules" that would be much appreciated.