What do you need to start your AWS environment?
When I joined the CyberLabs team, I realized that we would have a lot of work to do related to AWS infrastructure. And I needed to figure out where to start. I was hoping to develop a AWS Landing Zone, based on my previous experiences in another company, however, I discovered that I needed an AWS Architect to do that and I was not interested in multi-account for my goal right now.
Because I had the experience with the Landing Zone and only needed to setup few resources for an application, I needed to figure out how to setup an environment, where to start.
Setup a Network
I do recall to not pay that much attention on my classes of Network when I was in college. But now I needed that knowledge to understand how to create a safe network infrastructure on AWS. And how do you refresh your lost knowledge? Research!
After some googling, I have discovered that to build a safe network on AWS it is needed to understand how the following resources work:
The better place to know those concepts, are AWS Docs, and the related content are linked.
Terraform for the rescue
You shouldn't create AWS resources via the AWS Console, because you most probably will need to replicate that environment, and doing that via the console is a bad practice. I use the console just to explore some resources and see if something new was launched.
To create a VPC is not complicated, connecting the resources to make everything works are.
resource "aws_vpc" "this" {
cidr_block = var.vpc_cidr
}
Following the creation of the VPC, you need to connect an Internet Gateway, otherwise your resources won't be able to access internet:
resource "aws_internet_gateway" "this" {
vpc_id = aws_vpc.this.id
}
The Public Subnet: This is the place that will contain your Load Balancers and others AWS resources that need to be public available:
resource "aws_subnet" "public" {
availability_zone = var.availability_zones[count.index]
count = local.count
cidr_block = "${var.subnet_prefix}.${var.start_ip+count.index}.0/24"
vpc_id = aws_vpc.this.id
tags = {
Name = "Public-${var.name}-${var.availability_zones[count.index]}"
Tier = "Public"
}
}
In the above example I am creating a subnet in each Availability Zone, and building the CIDR of the subnet based on the user input vars.
Now, if we have a public subnet, we also need a private one, where our applications will be, where they wont be open to the internet. However they need to connect to the internet, so first, we need an Elastic Ip and a Nat Gateway:
resource "aws_eip" "nat_eip" {
vpc = true
depends_on = [aws_internet_gateway.this]
tags = {
Name = "${var.name}-eip"
}
}
resource "aws_nat_gateway" "this" {
allocation_id = aws_eip.nat_eip.id
subnet_id = element(aws_subnet.public.*.id, 0)
depends_on = [aws_internet_gateway.this]
tags = {
Name = "${var.name}-nat-gateway"
}
}
The Elastic IP will allow the resources on the private subnet to access the internet via our Internet Gateway. Now the Private Subnet:
resource "aws_subnet" "private" {
availability_zone = var.availability_zones[count.index]
count = local.count
cidr_block = "${var.subnet_prefix}.${var.start_ip+count.index}.0/24"
vpc_id = aws_vpc.this.id
tags = {
Name = "Private-${var.name}-${var.availability_zones[count.index]}"
Tier = "Private"
}
}
Now, to tie everything together, the Route Table. Note that we have two of them, one public and one private. One of them is the Default Route Table that is created together with the VPC, and on this structure it is our Private Route Table.
resource "aws_default_route_table" "this" {
default_route_table_id = aws_vpc.this.default_route_table_id
route {
cidr_block = "0.0.0.0/0"
nat_gateway_id = aws_nat_gateway.this.id
}
tags = {
Name = upper("RT_PRIVATE_${local.name}")
}
}
And we now connect our private subnets to that route table:
resource "aws_route_table_association" "this" {
count = local.count
route_table_id = aws_vpc.this.main_route_table_id
subnet_id = aws_subnet.private[count.index].id
}
Now the Public Route Table:
resource "aws_route_table" "public" {
vpc_id = aws_vpc.this.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.this.id
}
tags = {
Name = upper("RT_PUBLIC_${local.name}")
}
}
resource "aws_route_table_association" "this" {
count = local.count
subnet_id = aws_subnet.public[count.index].id
route_table_id = aws_route_table.public.id
}
And.... with all that we are good to go. Now we have a properly configured network infrastructure.
The full Terraform module that I have built for this you can find on this repository. Feel free to use it, change it, and push.
That's all folks. =D