We need to set up our network before we get into ECS and Jenkins. We'll stamp out a VPC, public subnets, private subnets, an Internet Gateway, NAT Gateways, and route tables. Let's get started!
First, create variables.tf. This file allows us to define the variables we need—a VPC CIDR block, private subnets, and public subnets.
variable "vpc_cidr_block" { description = "CIDR of vpc" type = string } variable "public_subnets" { description = "Map of public subnets that should be created" type = map(object({ cidr_block = string availability_zone = string })) } variable "private_subnets" { description = "Map of private subnets that should be created" type = map(object({ cidr_block = string availability_zone = string })) } variable "application_name" { description = "Name of the application" type = string }
Next, we'll provide the variable definitions in terraform.tfvars.
vpc_cidr_block = "10.0.0.0/24" public_subnets = { subnet_1 = { cidr_block = "10.0.0.0/26" availability_zone = "us-east-1a" } subnet_2 = { cidr_block = "10.0.0.64/26" availability_zone = "us-east-1b" } } private_subnets = { subnet_1 = { cidr_block = "10.0.0.128/26" availability_zone = "us-east-1a" } subnet_2 = { cidr_block = "10.0.0.192/26" availability_zone = "us-east-1b" } } application_name = "serverless-jenkins-on-ecs"
Now, create vpc.tf and create the VPC first. An AWS VPC (Virtual Private Cloud) is a virtual network logically isolated from other virtual networks in the AWS Cloud, providing you with control over IP addresses, subnets, route tables, and network gateways.
# VPC resource "aws_vpc" "this" { cidr_block = var.vpc_cidr_block enable_dns_hostnames = true tags = { Name = var.application_name } }
Create the public subnets. What makes these subnets public is that they will have a route to an Internet Gateway (IGW), which allows resources within the subnet to communicate directly with the Internet.
# Public Subnets resource "aws_subnet" "public" { for_each = var.public_subnets vpc_id = aws_vpc.this.id cidr_block = each.value.cidr_block availability_zone = each.value.availability_zone map_public_ip_on_launch = true tags = { Name = format("public-%s-%s", var.application_name, each.value.availability_zone) } }
Create the IGW and associate it with the VPC. We'll reference it later in our route table that we'll connect to our public subnets.
# IGW resource "aws_internet_gateway" "this" { vpc_id = aws_vpc.this.id }
Create a route table for your public subnet and add a route to funnel traffic through the IGW. After which, create the route table association to wire up the IGW with the public subnets.
# Public Route Table resource "aws_route_table" "public" { vpc_id = aws_vpc.this.id tags = { Name = "public" } } # Add IGW Route resource "aws_route" "public" { route_table_id = aws_route_table.public.id destination_cidr_block = "0.0.0.0/0" gateway_id = aws_internet_gateway.this.id } # Associate Route Table with Subnet resource "aws_route_table_association" "public" { for_each = aws_subnet.public subnet_id = each.value.id route_table_id = aws_route_table.public.id }
Next, create the private subnets. As the name implies, these subnets are inaccessible from the outside world.
# Private Subnets resource "aws_subnet" "private" { for_each = var.private_subnets vpc_id = aws_vpc.this.id cidr_block = each.value.cidr_block availability_zone = each.value.availability_zone tags = { Name = format("private-%s-%s", var.application_name, each.value.availability_zone) } }
Now, let's create an Elastic IP (EIP) and a NAT Gateway. We need the EIP, as AWS requires one as part of the NAT Gateway creation. The NAT Gateway is necessary as that's how the private subnets can communicate with the Internet (egress only). Imagine that you have RHEL EC2s that need to receive yum updates. You'll need a NAT Gateway.
# EIP for NAT Gateway resource "aws_eip" "this" { for_each = aws_subnet.private } # NAT Gateway resource "aws_nat_gateway" "this" { for_each = aws_subnet.private subnet_id = aws_subnet.public[each.key].id allocation_id = aws_eip.this[each.key].id tags = { Name = format("private-%s-%s", var.application_name, each.value.availability_zone) } }
Next, we'll create the route table, the route to associate the NAT Gateway to the private subnets, and the route table association.
# Private Route Table resource "aws_route_table" "private" { for_each = aws_subnet.private vpc_id = aws_vpc.this.id tags = { Name = format("private-%s-%s", var.application_name, each.value.availability_zone) } } # Add Route - Private Subnets to NAT Gateway resource "aws_route" "private" { for_each = aws_subnet.private route_table_id = aws_route_table.private[each.key].id destination_cidr_block = "0.0.0.0/0" nat_gateway_id = aws_nat_gateway.this[each.key].id } # Associate Private RT with Private Subnets resource "aws_route_table_association" "private" { for_each = aws_subnet.private subnet_id = each.value.id route_table_id = aws_route_table.private[each.key].id }
You are ready. Run the following commands.
# Initialize Terraform terraform init # Check and see what will be created terraform plan # Let's do this! terraform apply
Now, navigate to the AWS console and search for VPC.
Scroll down to the VPC resource map.
Click on subnets next.
Also, check out your Route Tables, Internet Gateways, NAT Gateways, and Elastic IPs.
Fin 👏
If you need it, here's the GitHub repo.
Top comments (0)