1

I am trying to create multiple Security Groups and rules within this group at the same time in a module for AWS.

I have a variable type like this below

variable "security_rules" {

      type = map(map(object({
        type        = string
        description = string
        from_port   = number
        to_port     = number
        protocol    = string
        cidr_blocks = list(string)
      })))
    }

And i am passing the values like this

security_rules = {
  internal_sg = {
    "rule1" = { type = "ingress", from_port = 22, to_port = 22, protocol = "tcp", cidr_blocks = ["0.0.0.0/0"], description = "For SSH" },
    "rule2" = { type = "ingress", from_port = 22, to_port = 22, protocol = "tcp", cidr_blocks = ["0.0.0.0/0"], description = "For SSH" }
  external_sg = {
    "rule1" = { type = "ingress", from_port = 22, to_port = 22, protocol = "tcp"
  }
}

Where internal_sg and external_sg would be security group name and there corresponding rules.

I am able to create the security groups but failing to add rules on top of that.

locals {
  name = var.security_rules
}

resource "aws_security_group" "ec2_security_groups" {
  for_each = local.name
  name   = each.key
  vpc_id = data.aws_vpc.selected.id
}
 

But i am just unable to make the logic for the security group rules

resource "aws_security_group_rule" "rules" {
  for_each          = { for k, v in local.name : k => v }
  type              = each.value.type
  from_port         = each.value.from_port
  to_port           = each.value.to_port
  protocol          = each.value.protocol
  cidr_blocks       = each.value.cidr_blocks
  description       = each.value.description
  security_group_id = aws_security_group.ec2_security_groups[each.key]
}

Error:

╷
│ Error: Missing map element
│ 
│   on ../../terraform-stacks/Stacks/security-group/main.tf line 19, in resource "aws_security_group_rule" "rules":
│   19:   type              = each.value.type
│     ├────────────────
│     │ each.value is map of object with 3 elements
│ 
│ This map does not have an element with the key "type".
╵
Marcin
  • 215,873
  • 14
  • 235
  • 294
Ali
  • 33
  • 6

1 Answers1

2

You have to flatten your variable first:


locals {
  flat_security_rules = merge([
      for sg, rules in var.security_rules:
         {
           for rule, vals in rules:
             "${sg}-${rule}" => merge(vals, {sg_name = sg})
         }
    ]...) # please, do NOT remove the dots
}

then

resource "aws_security_group_rule" "rules" {
  for_each          = local.flat_security_rules
  type              = each.value.type
  from_port         = each.value.from_port
  to_port           = each.value.to_port
  protocol          = each.value.protocol
  cidr_blocks       = each.value.cidr_blocks
  description       = each.value.description
  security_group_id = aws_security_group.ec2_security_groups[each.value.sg_name].id
}
Marcin
  • 215,873
  • 14
  • 235
  • 294
  • Sir u did some awesome VOODOO with the rules, but we are stuck at one point, it expect a security groups id and not name. – Ali Feb 07 '22 at 11:23
  • so this line `security_group_id = aws_security_group.ec2_security_groups[each.value.sg_name]` expects the exact sg names id to move ahead – Ali Feb 07 '22 at 11:24