DEV Community

Jay Watson
Jay Watson

Posted on

Standup Serverless Jenkins on Fargate with Terraform - Part 1: Networking

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
}
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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
  }
}
Enter fullscreen mode Exit fullscreen mode

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)
  }
}
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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)
  }
}
Enter fullscreen mode Exit fullscreen mode

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 network. 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)
  }
}
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Now, navigate to the AWS console and search for VPC.
AWS VPC
Scroll down to the VPC resource map.
VPC resource map
Click on subnets next.
AWS Subnets
Also, check out your Route Tables, Internet Gateways, NAT Gateways, and Elastic IPs.

Fin.

Top comments (0)