Availability Zone Subnetting

Hello All,

I am new to Terraform and Cloud Computing in general. I am trying to create a main.tf that sets up an AWS service and my main.tf looks like this:

data "aws_availability_zones" "zone_scaling" {}
#define AMI
data "aws_ami" "ubuntu" {
  most_recent = true
  owners      = ["099720109477"] # Canonical
  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-bionic-18.04-amd64-server-*"]
  }
}
resource "aws_vpc" "main_vpc" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_hostnames = true
  enable_dns_support   = true


  tags = {
    Name = "dev_vpc"
  }
}

resource "aws_subnet" "public_subnet" {
  vpc_id                  = aws_vpc.main_vpc.id
  cidr_block              = "10.0.1.0/24"
  map_public_ip_on_launch = true
  availability_zone       = "us-east-1a"

  tags = {
    Name = "dev_public_subnet"
  }
}

resource "aws_internet_gateway" "internet_gateway" {
  vpc_id = aws_vpc.main_vpc.id

  tags = {
    Name = "dev_igw"
  }
}

resource "aws_route_table" "public_route_table" {
  vpc_id = aws_vpc.main_vpc.id

  tags = {
    Name = "dev_public_route_table"
  }
}

resource "aws_route" "public_route" {
  route_table_id         = aws_route_table.public_route_table.id
  destination_cidr_block = "0.0.0.0/0"
  gateway_id             = aws_internet_gateway.internet_gateway.id
}

resource "aws_route_table_association" "public_route_table_association" {
  subnet_id      = aws_subnet.public_subnet.id
  route_table_id = aws_route_table.public_route_table.id
}

resource "aws_security_group" "public_security_group" {
  name        = "dev_public_security_group"
  description = "Allow inbound traffic from the internet"
  vpc_id      = aws_vpc.main_vpc.id


  ingress {
    description = "Allow inbound traffic from the internet"
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    description = "Allow outbound traffic to the internet"
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_key_pair" "key_pair" {
  key_name   = "dev_key_pair"
  public_key = file("~/.ssh/awskey.pub")
}

resource "aws_instance" "dev_node" {
  ami                         = "ami-08c40ec9ead489470"
  instance_type               = "t2.micro"
  key_name                    = aws_key_pair.key_pair.key_name
  associate_public_ip_address = true
  subnet_id                   = aws_subnet.public_subnet.id
  vpc_security_group_ids      = [aws_security_group.public_security_group.id]
  user_data                   = file("user_data_2.tpl")

  root_block_device {
    volume_type = "gp2"
    volume_size = 10
  }

  tags = {
    Name = "dev_node"
  }

  provisioner "local-exec" {
    command = templatefile("${var.host_os}-ssh-config.tpl", {
      hostname = self.public_ip,
      user     = "ubuntu",
    identity = "~/.ssh/awskey" })

    interpreter = var.host_os == "windows" ? ["cmd", "/c"] : ["bash", "-c"]
  }
}

data "aws_autoscaling_groups" "groups" {
  filter {
    name   = "key"
    values = ["Team"]
  }

  filter {
    name   = "value"
    values = ["Pets"]
  }
}

resource "aws_autoscaling_notification" "slack_notifications" {
  group_names = data.aws_autoscaling_groups.groups.names

  notifications = [
    "autoscaling:EC2_INSTANCE_LAUNCH",
    "autoscaling:EC2_INSTANCE_TERMINATE",
    "autoscaling:EC2_INSTANCE_LAUNCH_ERROR",
    "autoscaling:EC2_INSTANCE_TERMINATE_ERROR",
  ]

  topic_arn = "TOPIC ARN"
}

data "aws_subnets" "example" {
  filter {
    name   = "vpc-id"
    values = [var.vpc_id]
  }
}

data "aws_subnet" "example" {
  for_each = toset(data.aws_subnets.example.ids)
  id       = each.value
}

output "subnet_cidr_blocks" {
  value = [for s in data.aws_subnet.example : s.cidr_block]
}

# Declare the data source
data "aws_availability_zones" "available" {
  state = "available"
}

# e.g., Create subnets in the first two available availability zones

resource "aws_subnet" "primary" {
  vpc_id = var.vpc_id
  cidr_block = "10.0.0.0/24"
  availability_zone = "us-east-1b"
  

  # ...
}

resource "aws_subnet" "secondary" {
  vpc_id = var.vpc_id
  cidr_block = "10.0.0.0/24"
  availability_zone = "us-east-1c"
  

  # ...
}

resource "aws_lb_target_group" "target-group" {
  name     = "target-group"
  port     = 80
  protocol = "HTTP"
  vpc_id   = aws_vpc.main_vpc.id
}

resource "aws_lb" "load_balancer" {
  name               = "load-balancer"
  ip_address_type    = "ipv4"
  internal           = false
  load_balancer_type = "application"
  security_groups    = [aws_security_group.public_security_group.id]
  subnets            = data.aws_subnets.public_subnet.ids

  enable_deletion_protection = false
}

resource "aws_lb_listener" "listener" {
  load_balancer_arn = aws_lb.load_balancer.arn
  port              = "80"
  protocol          = "HTTP"

  default_action {
    target_group_arn = aws_lb_target_group.target-group.arn
    type             = "forward"
  }
}
 
 data "aws_subnets" "public_subnet" {
  filter {
    name   = "tag:Name"
    values = ["dev_public_subnet"]
  } 

 }

resource "aws_lb_target_group_attachment" "target-group-attachment" {
  target_group_arn = aws_lb_target_group.target-group.arn
  target_id        = aws_instance.dev_node.id
  port             = 80
}

resource "aws_autoscaling_group" "dev_autoscaling_group" {
  name                      = "dev_autoscaling_group"
  max_size                  = 2
  min_size                  = 1
  desired_capacity          = 1
  health_check_grace_period = 300
  health_check_type         = "ELB"
  launch_configuration      = aws_launch_configuration.dev_launch_configuration.name
  load_balancers            = [aws_lb.load_balancer.name]
  vpc_zone_identifier       = data.aws_subnets.public_subnet.ids
  target_group_arns         = [aws_lb_target_group.target-group.arn]
  tags = [
    {
      key                 = "Name"
      value               = "dev_autoscaling_group"
      propagate_at_launch = true
    },
    {
      key                 = "Team"
      value               = "Pets"
      propagate_at_launch = true
    },
  ]
}

resource "aws_launch_configuration" "dev_launch_configuration" {
  name_prefix                 = "dev_launch_configuration"
  image_id                    = "ami-08c40ec9ead489470"
  instance_type               = "t2.micro"
  key_name                    = aws_key_pair.key_pair.key_name
  associate_public_ip_address = true
  security_groups             = [aws_security_group.public_security_group.id]
  user_data                   = file("user_data_2.tpl")

  root_block_device {
    volume_type = "gp2"
    volume_size = 10
  }
} 




I am also trying to create two availability zone subnets within the same region, but I keep getting the following errors:

> Error: error creating EC2 Subnet: InvalidSubnet.Range: The CIDR '10.0.0.0/24' is invalid.
│       status code: 400, request id: d194ee54-cc57-447a-b2d3-f3761c79496a
│ 
│   with aws_subnet.primary,

│   on main.tf line 164, in resource "aws_subnet" "primary":
│  164: resource "aws_subnet" "primary" {
│ 
╵
╷
│ Error: error creating EC2 Subnet: InvalidSubnet.Range: The CIDR '10.0.0.0/24' is invalid.
│       status code: 400, request id: 33f3d44a-89c6-4fb5-a80a-1f374f1050d1
│ 
│   with aws_subnet.secondary,
│   on main.tf line 173, in resource "aws_subnet" "secondary":
│  173: resource "aws_subnet" "secondary" {
│ 
╵
╷
│ Error: creating application Load Balancer: ValidationError: At least two subnets in two different Availability Zones must be specified
│       status code: 400, request id: 2c5b27a0-8a8f-4e63-931e-f62f81993fa2
│ 
│   with aws_lb.load_balancer,
│   on main.tf line 189, in resource "aws_lb" "load_balancer":
│  189: resource "aws_lb" "load_balancer" {

Where am I going wrong? Thanks in advance for any assistance!

Hi @Bcopeland64,

It seems like both of the subnets mentioned in these error messages have the same CIDR block specified – both 10.0.0.0/24 – which isn’t valid because each subnet in a VPC must have separate address space.

Separately, it looks like your data.aws_subnets.public_subnet resource is trying to read the same object managed by aws_subnets.public_subnet, which is confusing Terraform because it can’t tell that the two are related and so it’s trying to read the subnets before they’ve been created, and therefore your load balancer effectively has zero subnets. To avoid that, in aws_lb.load_balancer set subnets to be a reference to the same resource that is declaring the existence of those subnets, so that Terraform can see that these two objects are connected.

(Your aws_subnet.public_subnet resource is declaring only one subnet, which isn’t sufficient to meet the minimum of two subnets in a load balancer, so you’ll also need to declare a second subnet and include its id as part of the subnets argument.