The requirements for this are to find all VPCs, create a Security Group in each one, find all running & stopped EC2 instances then attach this new security group to the primary interface to each instance. The TF file:
provider "aws" {
region = "us-east-1"
}
# Data block to store all VPCS
data "aws_vpcs" "all" {}
resource "aws_security_group" "vpc_sg" {
for_each = toset(data.aws_vpcs.all.ids)
name = "Example"
description = "Allows SSH access"
vpc_id = each.value
ingress {
from_port = 0
to_port = 22
protocol = "tcp"
cidr_blocks = ["1.1.1.0/27"] #Update for each environment
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
# Fetch all EC2 instances
data "aws_instances" "all" {
filter {
name = "instance-state-name"
values = ["running", "stopped"]
}
}
# Fetch instance details
data "aws_instance" "instance" {
for_each = toset(data.aws_instances.all.ids)
instance_id = each.key
}
# Fetch details of the network interfaces
# data "aws_network_interface" "interface" {
# #for_each = toset(flatten([for id in data.aws_instances.all.ids : data.aws_instance.instance[id].network_interface_id]))
# id = each.value
# }
# data "aws_network_interface" "interface" {
# for_each = toset([for id in data.aws_instances.all.ids : data.aws_instance.instance[id].network_interface_id])
# id = each.value
# }
# tolist(data.aws_instance.instance[id].network_interface_id)
# Attach Security Group only to instances NOT in an ASG
resource "aws_network_interface_sg_attachment" "attach_sg" {
for_each = {
for id in data.aws_instances.all.ids : id => (data.aws_instance.instance[id].network_interface_id)
if lookup(data.aws_instance.instance[id].tags, "aws:autoscaling:groupName", null) == null
}
security_group_id = aws_security_group.vpc_sg[data.aws_instance.instance[each.key].network_interface_id]
network_interface_id = data.aws_instance.instance[each.key].network_interface_id
}
# security_group_id = aws_security_group.vpc_sg[data.aws_network_interface.interface[data.aws_instance.instance[each.value].network_interface_id].vpc_id].id
# network_interface_id = each.value
# security_group_id = aws_security_group.vpc_sg[data.aws_instance.instance[each.key].network_interface_id]
# network_interface_id = data.aws_instance.instance[each.key].network_interface_id
I’ve also tried finding all network interfaces to select the primary one. It’s in a comment block above. Below the resource block commented out are other attempts to solve this.
---------------- terraform plan output ------------------------------------
data.aws_vpcs.all: Reading...
data.aws_instances.all: Reading...
data.aws_vpcs.all: Read complete after 0s [id=us-east-1]
data.aws_instances.all: Read complete after 1s [id=us-east-1]
data.aws_instance.instance["i-xxxxxxxxxxxxxxxxx"]: Reading...
data.aws_instance.instance["i-xxxxxxxxxxxxxxxxx"]: Reading...
<repeated output snipped>
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform planned the following actions, but then encountered a problem:
# aws_security_group.vpc_sg["vpc-xxxxxxxxxxxxxxxxx"] will be created
+ resource "aws_security_group" "vpc_sg" {
+ arn = (known after apply)
+ description = "Allows SSH access"
+ egress = [
+ {
+ cidr_blocks = [
+ "0.0.0.0/0",
]
+ from_port = 0
+ ipv6_cidr_blocks = []
+ prefix_list_ids = []
+ protocol = "-1"
+ security_groups = []
+ self = false
+ to_port = 0
# (1 unchanged attribute hidden)
},
]
+ id = (known after apply)
+ ingress = [
+ {
+ cidr_blocks = [
+ "10.0.0.0/8",
]
+ from_port = 0
+ ipv6_cidr_blocks = []
+ prefix_list_ids = []
+ protocol = "tcp"
+ security_groups = []
+ self = false
+ to_port = 22
# (1 unchanged attribute hidden)
},
]
+ name = "Example"
+ name_prefix = (known after apply)
+ owner_id = (known after apply)
+ revoke_rules_on_delete = false
+ tags_all = (known after apply)
+ vpc_id = "vpc-xxxxxxxxxxxxxxxxx"
}
# aws_security_group.vpc_sg["vpc-xxxxxxxxxxxxxxxxx"] will be created
+ resource "aws_security_group" "vpc_sg" {
+ arn = (known after apply)
+ description = "Allows SSH access"
+ egress = [
+ {
+ cidr_blocks = [
+ "0.0.0.0/0",
]
+ from_port = 0
+ ipv6_cidr_blocks = []
+ prefix_list_ids = []
+ protocol = "-1"
+ security_groups = []
+ self = false
+ to_port = 0
# (1 unchanged attribute hidden)
},
]
+ id = (known after apply)
+ ingress = [
+ {
+ cidr_blocks = [
+ "10.0.0.0/8",
]
+ from_port = 0
+ ipv6_cidr_blocks = []
+ prefix_list_ids = []
+ protocol = "tcp"
+ security_groups = []
+ self = false
+ to_port = 22
# (1 unchanged attribute hidden)
},
]
+ name = "Example"
+ name_prefix = (known after apply)
+ owner_id = (known after apply)
+ revoke_rules_on_delete = false
+ tags_all = (known after apply)
+ vpc_id = "vpc-xxxxxxxxxxxxxxxxx"
}
# aws_security_group.vpc_sg["vpc-xxxxxxxxxxxxxxxxx"] will be created
+ resource "aws_security_group" "vpc_sg" {
+ arn = (known after apply)
+ description = "Allows SSH access"
+ egress = [
+ {
+ cidr_blocks = [
+ "0.0.0.0/0",
]
+ from_port = 0
+ ipv6_cidr_blocks = []
+ prefix_list_ids = []
+ protocol = "-1"
+ security_groups = []
+ self = false
+ to_port = 0
# (1 unchanged attribute hidden)
},
]
+ id = (known after apply)
+ ingress = [
+ {
+ cidr_blocks = [
+ "10.0.0.0/8",
]
+ from_port = 0
+ ipv6_cidr_blocks = []
+ prefix_list_ids = []
+ protocol = "tcp"
+ security_groups = []
+ self = false
+ to_port = 22
# (1 unchanged attribute hidden)
},
]
+ name = "Example"
+ name_prefix = (known after apply)
+ owner_id = (known after apply)
+ revoke_rules_on_delete = false
+ tags_all = (known after apply)
+ vpc_id = "vpc-xxxxxxxxxxxxxxxxx"
}
Plan: 3 to add, 0 to change, 0 to destroy.
<repeated error snipped, it's the same for each instance>
│ Error: Invalid index
│
│ on main.tf line 70, in resource "aws_network_interface_sg_attachment" "attach_sg":
│ 70: security_group_id = aws_security_group.vpc_sg[data.aws_instance.instance[each.key].network_interface_id]
│ ├────────────────
│ │ aws_security_group.vpc_sg is object with 3 attributes
│ │ data.aws_instance.instance is object with 33 attributes
│ │ each.key is "i-xxxxxxxxxxxxxxxxx"
│
│ The given key does not identify an element in this collection value.
╵
For some reason I can’t figure out is why each.key has the instance ID and not the network interface ID.
Thanks for taking a look. --Mark