Issue creating AWS VPC Security Group within defined VPC

I’m trying to create a security group and associate it with a VPC created in my code, but when I try to apply it, I get an error telling me that it doesn’t exist in my default VPC, and therefore will not create it. It is only supposed to be referring to the VPC defined in my code, but when I run terraform apply, it references the default VPC instead.

Input:

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.37.0"
    }
  }
}

resource "aws_instance" "windows" {
  ami = "ami-0f9c44e98edf38a2b"
  instance_type = "t2.micro"
  associate_public_ip_address = true
  key_name = "terraform-key"
  subnet_id = "subnet-0a248f3e680da4aef"
  security_groups = [aws_security_group.allow_web.name]
  tags = {
    Name = "microTest"
  }
}

resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
  tags = {
    Name = "Project VPC"
  }
}

resource "aws_subnet" "public_subnets" {
  count = length(var.public_subnet_cidrs)
  vpc_id = aws_vpc.main.id
  cidr_block = element(var.public_subnet_cidrs, count.index)
  availability_zone = element(var.azs, count.index)

  tags = {
    Name = "Public Subnet ${count.index + 1}"
  }
}

resource "aws_subnet" "private_subnets" {
  count = length(var.private_subnet_cidrs)
  vpc_id = aws_vpc.main.id
  cidr_block = element(var.private_subnet_cidrs, count.index)
  availability_zone = element(var.azs, count.index)

  tags = {
    Name = "Private Subnet ${count.index + 1}"
  }
}

resource "aws_internet_gateway" "gw" {
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "Project VPC IG"
  }
}

resource "aws_route_table" "second_rt" {
  vpc_id = aws_vpc.main.id

  route{
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.gw.id
  }

  tags = {
    Name = "2nd Route Table"
  }
}

resource "aws_route_table_association" "public_subnet_asso" {
  count = length(var.public_subnet_cidrs)
  subnet_id = element(aws_subnet.public_subnets[*].id, count.index)
  route_table_id = aws_route_table.second_rt.id
}

resource "aws_security_group" "allow_web"{
  name = "allow_web_traffic"
  description = "allow web inbound traffic"
  vpc_id = aws_vpc.main.id

  ingress {
    description = "https"
    from_port = 443
    to_port = 443
    protocol = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  ingress {
    description = "http"
    from_port = 80
    to_port = 80
    protocol = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  ingress {
    description = "ssh"
    from_port = 2
    to_port = 2
    protocol = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  egress {
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    name = "allow_web"

  }
}

Output:

 Error: creating EC2 Instance: InvalidGroup.NotFound: The security group 'allow_web_traffic' does not exist in VPC 'vpc-060078657ca8ea948'│       status code: 400, request id: 392e7004-4ed6-4f0d-ae72-5deb6d205c50
│
│   with aws_instance.windows,
│   on main.tf line 10, in resource "aws_instance" "windows":
│   10: resource "aws_instance" "windows" {
│

In the aws_instance resource documentation, you will find the following note about security groups:

  • security_groups - (Optional, EC2-Classic and default VPC only) List of security group names to associate with.

Note: If you are creating Instances in a VPC, use vpc_security_group_ids instead.

Thus you should use the vpc_security_group_ids argument and include the security group ID in the list instead.

With the assumption that this is the block I change-

resource "aws_instance" "windows" {
  ami = "ami-0f9c44e98edf38a2b"
  instance_type = "t2.micro"
  # xlarge for later  
  # ami = "ami-0f9c44e98edf38a2b"
  # instance_type = "g4dn.xlarge"
  associate_public_ip_address = true
  key_name = "terraform-key"
  subnet_id = "subnet-0a248f3e680da4aef"
  vpc_security_group_ids = ["vpc-0887cab5853d18527"]
  tags = {
    Name = "microTest"
  }
}

I still get this same error-

Error: creating EC2 Instance: InvalidGroup.NotFound: The security group 'vpc-0887cab5853d18527' does not exist in VPC 'vpc-060078657ca8ea948'
│       status code: 400, request id: fc9f959f-10cc-4904-a0d2-e866ae82dbd2
│
│   with aws_instance.windows,
│   on main.tf line 10, in resource "aws_instance" "windows":
│   10: resource "aws_instance" "windows" {

Without quotes, though, just for testing purposes, I get this error-

Error: Invalid reference
│
│   on main.tf line 19, in resource "aws_instance" "windows":
│   19:   vpc_security_group_ids = [vpc-0887cab5853d18527]
│
│ A reference to a resource type must be followed by at least one attribute access, specifying the resource name.

I’m still somewhat at a loss of what I could change here to make this work, or if I’m just changing things in the wrong places.

The ID vpc-0887cab5853d18527 looks like a VPC ID, not a security group ID. You should double check and make sure you have the right reference - it should look something like sg-0796c1a96949b5c07. You can look up the security group ID in the EC2 console under Network & Security > Security Groups.

My mistake on that one-- but now I’m getting a fun similar error where it’s conflicting with the default subnet that’s linked to the default VPC:

 Error: creating EC2 Instance: InvalidParameter: Security group sg-02f1efa6466146146 and subnet subnet-0a248f3e680da4aef belong to different networks.
│       status code: 400, request id: 8a404c14-e0be-4384-906d-fb7f88531153
│
│   with aws_instance.windows,
│   on main.tf line 10, in resource "aws_instance" "windows":
│   10: resource "aws_instance" "windows" {

I have private and public subnets instantiated already.
I apologize if these are weird problems with actually really simple solutions, this is my first time making anything from scratch, and I’ve run into some really awkward problems from some mistakes I’ve made in the AWS console.

As the error message says, your security group and subnet reside in different VPCs. Based on past messages in the thread, your subnet seems to be in vpc-060078657ca8ea948 but your security group might be in vpc-0887cab5853d18527 which is the wrong ID used instead of the security group ID by mistake. You should ensure that the security group is created in vpc-060078657ca8ea948.

This specific problem I believe has been the root cause of all of my issues- at one point, early into development, I accidentally deleted the default VPC that was already instantiated within the AWS console. It’s been my belief that because I’m creating a new VPC, that this is not something that should matter, as I’m not using the default VPC. Am I misunderstanding the way that Terraform and AWS interface with one another?

If both the security group and VPC are being made with Terraform, how am I supposed to link it to the default VPC made in the AWS console?

(Additionally, if I set the vpc_id to the default VPC ID, it returns that it does not exist in the default VPC.)

If everything is created in Terraform and you are using references to set dependent attribute values, there should be no issue. So I suspect something is wrong with your Terraform configuration. Could you please provide your full configuration for further troubleshooting?

(P.S. If you deleted the default VPC and need to recreate it, you can run the CLI command: aws ec2 create-default-vpc You can run this in Cloud Shell if you don’t have AWS CLI locally. But wait until your Terraform is resolved so you don’t add more variables to the situation.)

Apologies, what’s the easiest/fastest way I can get that to you?

I think this forum allows you to attach/upload a file in a reply. You can redact any sensitive info you don’t want to share (just use *s or something) before you upload.

Which file specifically, I should’ve clarified, my bad

I am assuming that you just have one main.tf file or something similar for your Terraform configuration. If you have you multiple .tf, you can perhaps zip them up and upload the zip. Just make sure you strip any security sensitive info before doing so.

Apparently you can only send pictures in chats, so I’m going to have to do this the hard way. These are both of my .tf files.
main.tf:

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.37.0"
    }
  }
}

resource "aws_instance" "windows" {
  ami = "ami-0f9c44e98edf38a2b"
  instance_type = "t2.micro"
  # xlarge for later  
  # ami = "ami-0f9c44e98edf38a2b"
  # instance_type = "g4dn.xlarge"
  associate_public_ip_address = true
  key_name = "terraform-key"
  subnet_id = "subnet-0a248f3e680da4aef"
  vpc_security_group_ids = ["sg-02f1efa6466146146"]
  tags = {
    Name = "microTest"
  }
}

resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
  tags = {
    Name = "Project VPC"
  }
}

resource "aws_subnet" "public_subnets" {
  count = length(var.public_subnet_cidrs)
  vpc_id = aws_vpc.main.id
  cidr_block = element(var.public_subnet_cidrs, count.index)
  availability_zone = element(var.azs, count.index)

  tags = {
    Name = "Public Subnet ${count.index + 1}"
  }
}

resource "aws_subnet" "private_subnets" {
  count = length(var.private_subnet_cidrs)
  vpc_id = aws_vpc.main.id
  cidr_block = element(var.private_subnet_cidrs, count.index)
  availability_zone = element(var.azs, count.index)

  tags = {
    Name = "Private Subnet ${count.index + 1}"
  }
}

resource "aws_internet_gateway" "gw" {
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "Project VPC IG"
  }
}

resource "aws_route_table" "second_rt" {
  vpc_id = aws_vpc.main.id

  route{
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.gw.id
  }

  tags = {
    Name = "2nd Route Table"
  }
}

resource "aws_route_table_association" "public_subnet_asso" {
  count = length(var.public_subnet_cidrs)
  subnet_id = element(aws_subnet.public_subnets[*].id, count.index)
  route_table_id = aws_route_table.second_rt.id
}

resource "aws_security_group" "allow_web"{
  name = "allow_web_traffic"
  description = "allow web inbound traffic"
  vpc_id = "vpc-060078657ca8ea948"

  ingress {
    description = "https"
    from_port = 443
    to_port = 443
    protocol = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  ingress {
    description = "http"
    from_port = 80
    to_port = 80
    protocol = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  ingress {
    description = "ssh"
    from_port = 2
    to_port = 2
    protocol = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  egress {
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    name = "allow_web"

  }
}

variables.tf:

variable "public_subnet_cidrs" {
    type = list(string)
    description = "public subnet cidr values"
    default = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
}

variable "private_subnet_cidrs" {
    type = list(string)
    description = "private subnet cidr values"
    default = ["10.0.4.0/24", "10.0.5.0/24", "10.0.6.0/24"]
}

variable "azs" {
    type = list(string)
    description = "Availability Zones"
    default = ["us-east-1a", "us-east-1b", "us-east-1c"]
}

In your configuration you have the following hardcoded:

  1. subnet_id in aws_instance.windows
  2. vpc_security_group_ids in aws_instance.windows
  3. vpc_id in aws_security_group.allow_web

They should be changed to the following (subnet I am just guessing):

  1. aws_subnet.public_subnets[0].id
  2. aws_security_group.allow_web.id
  3. aws_vpc.main.id

Fixing these should unblock you, but I think you have bigger problems to deal with. Here are some issues I see:

  1. You don’t have a NAT gateway set up and routing configured for the private subnets. It’s fine for now if you are not using it, but you’ll eventually need to configure them.
  2. Your security group is wide open to the internet. Aside from the insecure HTTP port, you also have SSH opened. You need to lock it down before you go any further!
  3. I don’t know what your AMI ID points to, but it seems to be a Windows AMI. So you’d probably need RDP instead of SSH access. I recommend that you investigate using SSM Session Manager instead of opening SSH or RDP ports if you are in doubt.
  4. I would recommend manually using an Elastic IP for the EC2 instance over using associate_public_ip_address in aws_instance.
  5. I actually tried to run your configuration but the EC2 instance wouldn’t start. The AMI seems to be for Windows so I am not sure if t2.micro is good enough to run it.

My recommendation is for you to review more AWS security best practices and play more with Terraform before you do anything complex with GPU instances. For the former, I wrote a blog series on implementing AWS Startup Security Baseline (SSB) using Terraform earlier in case you are interested (part 3 and 4 are about workload security): How to implement the AWS Startup Security Baseline (SSB) using Terraform - Sharing Field Experiences on AWS, Azure, and DevOps | Avangards Blog

Oh yeah, fully setting up a gateway was the next step I was going to take before running into all of these problems. I had a security group written for RDP, but rewrote it into this to see if it fixed any of my problems, which it did not.
This was the security group I had written before, though I’m certain it doesn’t follows every best practice-

resource "aws_security_group" "allow_rdp" {
  name = "allow_rdp"
  description = "rdp"
  vpc_id = aws_vpc.main.id
  ingress {
    from_port = 3389
    to_port = 3389
    protocol = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  egress{
    from_port = 0
    to_port = 0
    protocol = -1
    cidr_blocks = ["0.0.0.0/0"]
  }
}

In general, never use 0.0.0.0/0 for any inbound rules unless there is a very valid reason to. If you must, set it to your home or work IP address (with /32 prefix for one IP). You can find your IP address by Googling “what is my IP” or asking IT for your company network’s external IP CIDRs. Hope this answers all your questions concerning this thread.

Here’s hoping so, thank you so much!!