VPC Networks, Subnetworks, and Firewall in GCP Using Terraform.

·

7 min read

Okay, First things first. This blog will not be about provisioning infrastructure in GCP using Terraform. You’ll get a lot of blogs or videos regarding provisioning the above things using Terraform and honestly, there is no use in doing repetitive work for the things which are already available on the internet.

While I started working on GCP, I had knowledge of Terraform and AWS. So, Comparatively, I didn’t have to start everything at zero but in case you don’t have much idea about Terraform, You can always refer to the official documentation of Terraform which will help you to get the complete idea about it.

What I’ll cover?

  • The use of some unique attributes is generally not mentioned in Terraform’s example usage.
  • Why do we use them?
  • As we are working on the most critical part which is Networking in any cloud, How we can create a secure infrastructure using VPC Networks, Subnetworks, and Firewalls?
  • Bonus points for those who already know AWS.

Architecture

GCP-VPC-Subnets-Firewall.png

Code Structure

I did make use of custom modules to write the Terraform scripts which is basically the best practice in DevOps as it reduces the code redundancy and we can reuse them wherever we want.

image.png

You must be seeing a lot of files above. We’ll understand each one of them one by one.

Credentials have the admin.json which is nothing but the JSON key of my service account. I use it for authentication purposes between Terraform and my GCP account.

CustomModules consists of Compute, Scripts, and VPC. We will be just seeing the VPC module in this blog and in the next one, we’ll talk about what’s inside the Compute and Scripts. For now, you can ignore them.

RootModule is nothing but the root directory. As you can see Terraform state files and much other stuff there. I am hoping you know the Terraform before reading this that’s why I am not explaining what each file means in the root directory.

Terraform Script for VPC Network

#################### Custom VPC ####################

resource "google_compute_network" "vpc_network" {
  project                 = var.project
  name                    = "custom-vpc-network"
  auto_create_subnetworks = false
  mtu                     = 1460  ## Maximun Transmission Unit in Bytes (Max Value = 1500)
}

Yes, This much code is enough to create a custom VPC Network. By default, Terraform creates auto-mode VPC which is nothing but with Subnetworks but as I wanted to create Subnetworks on my own I have kept auto_create_subnetworks = false as this value is true by default.

This will create VPC Network named custom-vpc-network with zero Subnetworks in it.

Terraform Script for Subnetworks

Before moving to the script, I created six Subnetworks which consist of two public Subnetworks and two private Subnetworks for application purposes and two private Subnetworks for database purposes.

#################### Application Public Subnets ####################

resource "google_compute_subnetwork" "application-public-subnet1" {
  name          = "application-public-subnet1"
  ip_cidr_range = var.app-public-subnet1-cidr
  region        = var.region
  network       = google_compute_network.vpc_network.id
}

resource "google_compute_subnetwork" "application-public-subnet2" {
  name          = "application-public-subnet2"
  ip_cidr_range = var.app-public-subnet2-cidr
  region        = var.region
  network       = google_compute_network.vpc_network.id
}

#################### Application Private Subnets ####################

resource "google_compute_subnetwork" "application-private-subnet1" {
  name          = "application-private-subnet1"
  ip_cidr_range = var.app-private-subnet1-cidr
  region        = var.region
  network       = google_compute_network.vpc_network.id
}

resource "google_compute_subnetwork" "application-private-subnet2" {
  name          = "application-private-subnet2"
  ip_cidr_range = var.app-private-subnet2-cidr
  region        = var.region
  network       = google_compute_network.vpc_network.id
}

#################### Database Private Subnets ####################

resource "google_compute_subnetwork" "database-private-subnet1" {
  name          = "database-private-subnet1"
  ip_cidr_range = var.db-private-subnet1-cidr
  region        = var.region
  network       = google_compute_network.vpc_network.id
}

resource "google_compute_subnetwork" "database-private-subnet2" {
  name          = "database-private-subnet2"
  ip_cidr_range = var.db-private-subnet2-cidr
  region        = var.region
  network       = google_compute_network.vpc_network.id
}

Okay, Nothing fancy here. Every Subnetwork must be looking the same with differences in names and CIDR ranges. I’ll explain one so you’ll get an idea about others. I created every Subnetwork in the same region and I made sure that I am passing the VPC Network ID of the custom VPC we created above which will cause these Subnetworks to be created inside that custom VPC. While defining CIDR ranges just keep one thing in mind you cannot overlap the CIDR ranges.

e.g. CIDR_1 = 10.20.30.0/24 and CIDR_2 = 10.20.0.0/16

The above CIDR ranges overlap, Which is not acceptable.

Till now we are ready with one custom VPC Network and six Subnetworks out of which two are public and four are private.

Now you must be thinking what is that thing that is making these Subnetworks categorized into public and private?

Public Subnetworks must have access to the internet and private Subnetworks should not. Where if you want to give internet access to private Subnetworks then you must have configured NAT Gateway which is a vast topic in itself and maybe we can see that in some different blogs but as of now to cut the internet access of private Subnetworks what you can do is, Delete the route which got created by default while we created the Subnetworks. This route gets created to make sure your Subnetworks are connected to Internet Gateway so that they can be accessed over the public internet.

Terraform Script for Firewalls

This is one of the important topics as through Firewalls we can manage incoming and outgoing network traffic. So, When it comes to secure infrastructure this becomes important by default.

#################### Firewall for Application Public Subnets ####################

resource "google_compute_firewall" "public-firewall" {
  name    = "public-firewall"
  network = google_compute_network.vpc_network.name

  allow {
    protocol = "icmp"
  }

  allow {
    protocol = "tcp"
    ports    = var.public-firewall-ports
  }

  source_ranges = [ "0.0.0.0/0" ] ## This firewall has opened to internet. So, Make sure you are attaching this firewall only to those VMs which you want to be available to public internet
  target_tags = [ "web-public" ]  ## Remember to add this tag to VMs in Public Subnet
}

#################### Firewall for Application Private Subnets ####################

resource "google_compute_firewall" "private-firewall" {
  name    = "private-firewall"
  network = google_compute_network.vpc_network.name

  allow {
    protocol = "icmp"
  }

  allow {
    protocol = "tcp"
    ports    = var.private-firewall-ports
  }

  source_ranges = [ var.app-public-subnet1-cidr, var.app-public-subnet2-cidr, var.app-private-subnet1-cidr, var.app-private-subnet2-cidr, var.db-private-subnet1-cidr, var.db-private-subnet2-cidr ]  ## Allowing traffic only from defined subnet cidrs
  target_tags = [ "web-private" ]  ## Remember to add this tag to VMs in Private Subnet
}

#################### Firewall for Database Public Subnets ####################

resource "google_compute_firewall" "db-firewall" {
  name    = "db-firewall"
  network = google_compute_network.vpc_network.name

  allow {
    protocol = "icmp"
  }

  allow {
    protocol = "tcp"
    ports    = var.db-firewall-ports
  }

  source_ranges = [ var.app-public-subnet1-cidr, var.app-public-subnet2-cidr, var.app-private-subnet1-cidr, var.app-private-subnet2-cidr, var.db-private-subnet1-cidr, var.db-private-subnet2-cidr ]  ## Allowing traffic only from defined subnet cidrs
  target_tags = [ "db-private" ]  ## Remember to add this tag to DBs in Private Subnet
}

In my opinion, the three important things were: Which ports you kept open, The source range (From which range the traffic will be expected), and target tags.

  • While deciding the ports, Only open necessary ports like 22 (SSH), 80 (HTTP), and 443 (HTTPS). And if you are hosting your application on any server then the specific port number for that server. e.g. 8080 (Tomcat). Remember I am talking about the incoming (Inbound) traffic. For outgoing (Outbound) traffic, If you haven’t configured anything it’ll be fine.
  • The source range will make sure your Firewall is accepting the incoming traffic only from the specified CIDR range. So, For public Subnetworks, it can be 0.0.0.0/0 (Open to the internet) and for private Subnetworks, it can be customized as you can only accept the traffic from CIDRs which has been assigned to your Subnetworks. This will make sure any request outside your VPC is not going to serve by your Firewalls.
  • Now, Target tags. By default, Any Firewall you created in your VPC Network will get assigned to any VM which is getting created in the same VPC Network which is horrible. So, Target tags help us in attaching a necessary Firewall to a particular instance. e.g. Public Firewall will only be assigned to VMs which has been created in public Subnetworks and the same goes for private Subnetworks.

Hush, This is it. We have the Networking part ready. The so-called complex one.

Read the comments that I have specified in the code. It will help you to understand better.

Comparison with AWS

  • VPC Networks, Subnetworks, and Firewalls are VPC, Subnets, and Security Groups respectively.
  • A service Account is nothing but IAM User with appropriate IAM Roles.
  • JSON keys can act as Access and Secret Keys.
  • VPC Network is a global service in GCP whereas VPC is a regional service in AWS.

https://github.com/NihalSatbhai/GCP-Terraform