Terraform: how to create a reusable module to create aws security groups

37 Views Asked by At

I need to setup a module to create aws security group, which can be used to create multiple secuiryt groups with differnt port and CIDR value. For example, Security group for Ec2 will need port 80 and 443 to internet, another ec2 with port 8000 only, for rds with port 5432 from secuity groups of the 2 ec2's, for redis with port 6379 from secuity groups of the 2 ec2's.

  dynamic "ingress" {
    iterator = port
    for_each = var.ingress_ports
    content {
      description = "HTTP connection from Web"
      from_port        = port.value
      to_port          = port.value
      protocol         = "tcp"
      cidr_blocks      = ["0.0.0.0/0"]
      ipv6_cidr_blocks = ["::/0"]
    }
  }

I tried with for_each and pass port as values, but i need a way to loop or reference other security group from env variables. In sum cases the CIDR will an IP in some other it will be another securoty group. Is there a way to address this.

1

There are 1 best solutions below

1
Дмитро Іванов On

First of all, you can use not ingress block of the aws_security_group resource, but a separate aws_vpc_security_group_ingress_rule resource which makes your way of using loops much more flexible, then with the dynamic block. Then, when you can create an input variable, which contains not a simple list of ips, but a complex object, containing the ingress rules data:

variable "ingress_ips" {
  type = list(object({
    ip = string
    from_port = number
    to_port = number
    ip_protocol = string
  }))
  default = []
}

Now you can use foreach for the aws_vpc_security_group_ingress_rule resource

resource "aws_vpc_security_group_ingress_rule" "ip_ingress_rule" {
 for_each = { for ip in var.ingress_ips : "${ip.ip}${ip.from_port}${ip.ip_protocol}" => ip }
  security_group_id = aws_security_group.this.id
  cidr_ipv4 = "${each.value.ip}"
  from_port = each.value.from_port
  to_port = each.value.to_port
  ip_protocol = "${each.value.ip_protocol}"
  
  depends_on = [
    aws_security_group.this
  ]
}

The tricky part of mapping list to map and creating a complex key is due to that terraform wants to iterate over the unique collection: a set or a map with unique keys. You can not cast a list of objects to set, so you need to create a map.

To create rules for security groups you do just the same: create a variable with list of objects, in which instead of ip you have a security_group_id and map it to the referenced_security_group_id in the aws_vpc_security_group_ingress_rule resource.