Assigning a Security Group to all EC2 Instance Primary Interface Fails

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