2
votes

Requirement:- I have multiple group(say 2 groups) of EC2s where each group contain 6 EC2. and I have to attach different SG to each group.
Example:-
Group1 contains :- Head1, child :EC2-1, EC2-2....6 and need to attach SG1
Group2 contains :- Head2, child :EC2-3, EC2-4 ...6 and need to attach SG2

I don't want to write separate resource "aws_instance" Head-Module

    resource "aws_security_group" "sg" {
    count       = var.ec2_instance_count
  name        = "${local.account}${count.index}"
  vpc_id      = local.vpc_id
}

  resource "aws_instance" "ec2_instance" {
  count           = var.ec2_instance_count
  security_groups = [element(aws_security_group.sg.*.id, count.index)]
}

Child-Module:

  data "aws_security_groups" "data_security_group" {
      filter {
        name   = "group-name"
        values =  ["${local.account}${count.index}"]
      }
    }
   resource "aws_instance" "ec2_child" {
  count           = var.ec2_instance_count*var.numberofchild
  security_groups = [element(aws_security_group.data_security_group.*.id, count.index)]
}

Error: Error launching source instance: InvalidGroup.NotFound: The security group 'terraform-2020082 4151444795600000001' does not exist in VPC 'vpc-ghhje85abcy' status code: 400, request id: 9260fd88-a03a-4c46-b67c-3287594cdab5

on main.tf line 68, in resource "aws_instance" "ec2_instance": 68: resource "aws_instance" "ec2_instance" {

Note: I am using data "aws_security_groups" instead of data "aws_security_group". If I use the later one, I know I will be able to get only one SG in the data resource and it throws me an error :multiple Security Groups matched; from which I kind of moved ahead by using data "aws_security_groups" and this error get vanished. but the latest error I m facing is: InvalidGroup.NotFound as mentioned above.

Update: I am able to use data resource and able to attach the different SG to different EC2. the only issue is random Sequencing. for all 6 EC2 of group 1 I want them to assign first SG and so on.

2

2 Answers

2
votes

Don't use the data, instead create your resource "aws_security_group" using a count like you do on your resource "aws_instance" that way you can reference them directly...

resource "aws_security_group" "sg" {
  count       = var.ec2_instance_count
  name        = "${local.account}${count.index}"
  vpc_id      = local.vpc_id
}

resource "aws_instance" "ec2_instance" {
  count           = var.ec2_instance_count
  security_groups = [element(aws_security_group.sg.*.id, count.index)]
}
1
votes

Thanks Helder, I created the resource with count. its not the huge infrastructure but a fairly complex one. 8 groups (each group has 1 Parent and 6 child EC2) There is 1 External SG for all parents. and 8 internal SG 1 for each group). I had to follow a sequence of provisioning because the requirement was to pass the "Parent Host name" to respective group of Childs in "Childs User data" so I had to keep them in a separate modules and used "data" resources for reuse.

ParentModule:

resource "aws_instance" "ec2_instance" {
  count                   = tonumber(var.mycount)
 vpc_security_group_ids  = [data.aws_security_group.external_security_group.id, element(data.aws_security_group.internal_security_group.*.id, count.index)]
...
}
resource "aws_security_group" "internal_security_group" {
  count       = tonumber(var.mycount)
  name        = "${var.internalSGname}${count.index}"
}

resource "aws_security_group" "external_security_group" {
  name        = ${var.external_sg_name}"
}

ChildModule: with Data resource and used dynamic map to assignment of SG to Proper group of EC2.

data "aws_security_group" "internal_security_group" {
  count = tonumber(var.mycount)
  filter {
    name   = "group-name"
    values = "${var.internalSGname}${count.index}"]
  }
}
resource "aws_instance" "ec2_child" {
  count                   = local.child_count * tonumber(var.mycount)
  vpc_security_group_ids  = ["${element(data.aws_security_group.internal_security_group.*.id, "${lookup(local.SG_lookup, count.index, 99)}")}"]

variable.tf
locals{
 SG_lookup = {
    for n in range(0, (local.child_count * tonumber(var.mycount))) :
    n => "${floor(((n) / local.child_count))}"
  }
 }
}