Attach multiple security group to EC2 instance

Hello,
How to attach multiple security groups at EC2 creation?
networking/main.tf
#Web Server Security Group
resource “aws_security_group” “web_sg” {
name = “web_sg”
description = “This security group will control the private Web Servers”
vpc_id = aws_vpc.perf_vpc.id
egress {
from_port = 0
to_port = 0
protocol = “-1”
cidr_blocks = [“0.0.0.0/0”]
}
}
#Load Balancer Security Group
resource “aws_security_group” “alb_sg” {
name = “alb_sg”
description = " This secruity group is for Application Load Balancer"
vpc_id = aws_vpc.perf_vpc.id
egress {
from_port = 0
to_port = 0
protocol = “-1”
cidr_blocks = [“0.0.0.0/0”]
}
}
resource “aws_security_group” “perf_pvt_sg” {
name = “perf_pvt_sg”
description = “Aptean_Base-Perf_Pvt”
vpc_id = aws_vpc.perf_vpc.id
depends_on = [aws_security_group.bastion_sg]
ingress {
description = “kaspersky”
from_port = 0
to_port = 0
protocol = “-1”
cidr_blocks = [“10.176.0.35/32”]
}
egress {
from_port = 0
to_port = 0
protocol = “-1”
cidr_blocks = [“0.0.0.0/0”]
}
}

networking/outputs.tf
output “perf_pvt_sg” {
value = aws_security_group.perf_pvt_sg.id
}
output “web_sg” {
value = aws_security_group.web_sg.id
}
output “alb_sg” {
value = aws_security_group.alb_sg.id
}

root/main.tf
#Deploy Web Servers
module “web_servers” {
source = “./web_servers”
keyname = module.domain_controllers.key_name
public_key_path = var.public_key_path
web_count = var.web_count
web_inst_type = var.web_inst_type
pvtsubnets = module.networking.private_subnets
web_sg = [
module.networking.web_sg,
module.networking.perf_pvt_sg,
module.networking.alb_sg
]
}

Everything is fine and gets created as expected and terraform output also shows the resources, but all the EC2 instances (in this case, I am just pointing the web servers) have the default Security Group attached.I do see, all other security groups created though none are attached.
I tried to switch web_sg as id and name attribute as well:

web_sg          = [
        module.networking.web_sg.id,
        module.networking.perf_pvt_sg.id,
        module.networking.alb_sg.id
        ]

This throws error:

Error: Unsupported attribute

  on main.tf line 46, in module "web_servers":
  46:     module.networking.web_sg.name,
    |----------------
    | module.networking.web_sg is "sg-008001301c71877a9"
This value does not have any attributes.


Error: Unsupported attribute

  on main.tf line 47, in module "web_servers":
  47:     module.networking.perf_pvt_sg.name,
    |----------------
    | module.networking.perf_pvt_sg is "sg-0a50f754aceaae6cd"

This value does not have any attributes.


Error: Unsupported attribute

  on main.tf line 48, in module "web_servers":
  48:     module.networking.alb_sg.name
    |----------------
    | module.networking.alb_sg is "sg-05c898e0b6873c411"

This value does not have any attributes.

Can someone please suggest me what am I doing wrong?
AWS Console:


Hi

Your security groups module is already exporting the group id, as perf_pvt_sg and so on… so probably there is not need ad .id to the ec2 instance security groups.

See a similar example:

https://www.itwonderlab.com/en/terraform-aws-ec2-security-rules/

Hi,
Thank you for your response. However, even when I just run with just this block, security groups get created, but they dont get attached to the instances. Rather the default security group gets attached:
web_sg = [
module.networking.web_sg,
module.networking.perf_pvt_sg,
module.networking.alb_sg
]
As shown in the AWS Console screenshots. Also to add, terraform plan also doesnt show any error or warning of any sort. It appears Terraform is assuming to attach the default security group rather than the ones I want.

Review the module that creates the EC2 instance.

Is the module doing anything with web_sg parameter? It should be assigning those ids to the security groups of the created Instance.

Good catch. While the module main.tf did not have any reference of web_sg, I set the module variables.tf with this input: variable “web_sg” {}
I tweaked it a bit and here are the module snippets:

web_server/main.tf
#Web Server

resource "aws_instance" "web" {
  count         = var.web_count
  ami           = data.aws_ami.server_ami.id
  ebs_optimized = true
  instance_type = var.web_inst_type
  subnet_id = element(var.pvtsubnets, count.index)
  credit_specification {
    cpu_credits = "standard"
  }
  root_block_device {
    volume_type = "gp2"
    volume_size = 80
    encrypted   = true
    kms_key_id  = "1d9ef127-cc8f-4dda-9bdf-abdad498ea6f"
  }
  ebs_block_device {
    device_name = "/dev/sdf"
    volume_type = "gp2"
    volume_size = 40
    encrypted   = true
    kms_key_id  = "1d9ef127-cc8f-4dda-9bdf-abdad498ea6f"
  }
  tags = {
    Name = "PerformanceWeb0${count.index + 1}"
  }
}

#-----web_servers/variables.tf

variable "keyname" {}
variable "public_key_path" {}
variable "web_count" {}
variable "web_inst_type" {}
variable "pvtsubnets" {
  type = list(string)
}
variable "webserver_sg" {}

root/main.tf

#Deploy Web Servers
  module "web_servers" {
  source          = "./web_servers"
  keyname         = module.domain_controllers.key_name
  public_key_path = var.public_key_path
  web_count       = var.web_count
  web_inst_type   = var.web_inst_type
  pvtsubnets      = module.networking.private_subnets
  webserver_sg = [
    module.networking.web_sg,
    module.networking.perf_pvt_sg,
    module.networking.alb_sg
  ]
}

The situation is still the same, EC2 instances with default security group and not the listed ones.
The security groups are defined in networking module
networking/main.tf

#Web Server Security Group
resource “aws_security_group” “web_sg” {
name = “web_sg”
description = “This security group will control the private Web Servers”
vpc_id = aws_vpc.perf_vpc.id
egress {
from_port = 0
to_port = 0
protocol = “-1”
cidr_blocks = [“0.0.0.0/0”]
}
}
#Load Balancer Security Group
resource “aws_security_group” “alb_sg” {
name = “alb_sg”
description = " This secruity group is for Application Load Balancer"
vpc_id = aws_vpc.perf_vpc.id
egress {
from_port = 0
to_port = 0
protocol = “-1”
cidr_blocks = [“0.0.0.0/0”]
}
}
resource “aws_security_group” “perf_pvt_sg” {
name = “perf_pvt_sg”
description = “Aptean_Base-Perf_Pvt”
vpc_id = aws_vpc.perf_vpc.id
depends_on = [aws_security_group.bastion_sg]
ingress {
description = “kaspersky”
from_port = 0
to_port = 0
protocol = “-1”
cidr_blocks = [“10.176.0.35/32”]
}
egress {
from_port = 0
to_port = 0
protocol = “-1”
cidr_blocks = [“0.0.0.0/0”]
}
}

networking/outputs.tf

output “perf_pvt_sg” {
value = aws_security_group.perf_pvt_sg.id
}
output “web_sg” {
value = aws_security_group.web_sg.id
}
output “alb_sg” {
value = aws_security_group.alb_sg.id
}

I am a new learner of Terraform. Pardon my naivety. Would appreciate some direction here.

Got it sorted!

As I review the code, it appears since I had commented vpc_security_group_ids in the web_servers module, it was taking the VPC default security group. Made a few changes as below:

web_servers/main.tf

#Web_servers
resource "aws_instance" "web" {
  count         = var.web_count
  ami           = data.aws_ami.server_ami.id
  ebs_optimized = true
  instance_type = var.web_inst_type
  subnet_id     = element(var.pvtsubnets, count.index)
  vpc_security_group_ids = [
    var.web_sg,
    var.perf_pvt_sg,
    var.alb_traffic_sg
  ]

web_servers/variable.tf

variable "web_sg" {}
variable "perf_pvt_sg" {}
variable "alb_traffic_sg" {}

root/main.tf

#Deploy Web Servers
module "web_servers" {
  source            = "./web_servers"
  keyname           = module.domain_controllers.key_name
  public_key_path   = var.public_key_path
  web_count     = var.web_count
  web_inst_type = var.web_inst_type
  pvtsubnets        = module.networking.private_subnets
  web_sg        = module.networking.web_sg
  perf_pvt_sg       = module.networking.perf_pvt_sg
  alb_traffic_sg       = module.networking.alb_traffic_sg
}

Desired Output