Provisioning Vm's on private and public subnet in GCP
Infrastructure as code with terraform

Prerequisites
- GCP account
- Linux Operating System (Preferably Ubuntu 20.04LTS or WSL on Windows)
What you will learn
- How to install terraform on Ubuntu
- How to create a project on GCP
- How to create service account with necessary permissions for terraform
- How to create GCP credentials and download
- How to enable appropriate API's for terraform
- How to configure terraform files
- How to executes terraform files
Installing Terraform
Use the commands below to install terraform on your operating system.
sudo apt update
- Run
updatecommand to update package repositories and get latest package information four operating system.
$ wget https://releases.hashicorp.com/terraform/0.14.3/terraform_0.14.3_linux_amd64.zip
- Run
wgetcommand to download the terraform files from the releases repository. This command executes to downloadterraform version 0.14.3inzipformat. You might need to installwgetif terminal output iswget command not found; use below command to install wget.
sudo apt install wget
- After successfully installing
wgetif not previously installed, then run below command to unzip the downloaded terraform file.
sudo apt install zip -y
sudo unzip terraform_0.14.3_linux_amd64.zip
- The first command
sudo apt install zip -yinstall zip package on your operating system while the second command unzip the terraform file. After the file have been unzipped, you will need to move it into yourbin folder. Thebin foldercontains allexecutables filesrequired for minimal system working. Use below command to move the unzipped files.
sudo mv terraform /usr/local/bin/
- After using the
mvcommand to move terraform files into the bin; then, you can check the version of terraform to ensure the installation is successful. This can be achieved with below command:
terraform version
Creating Project on GCP
- Here, after logging in to your GCP account, on your home page in the search bar; type
Manage Resourcesand on the search results highlighted in circles as shown below.

- Then, click on
create projectas circled.

- Afterwards, fill in the project name, you can also edit the project id. The project id can only be edited at the point of creation, select an organization if applicable. Then click on create as indicated below

- After clicking on create, it redirects you back to the manage resources page where the newly created project is listed.

Creating Service Account with Appropriates Roles and Permissions
- After the project have been created, navigate to
IAM & Adminand selectService Accountsas shown below

- On the service account page, select
CREATE SERVICE ACCOUNTand ensure the service account is created in the preferred project.
On the new page, you have been redirected to, fill in the
service account nameanddescription of the service account; then clickCREATE.
After creating the service account, then you need to add roles and permissions to the service account. Below are roles needed on the service account for terraform to access project on GCP:
Storage Admin → which grants Full access to Google Cloud Storage
Compute Admin → which grants Full control of Compute Engine resources (Virtual Machines)
- After adding all the roles, click on
continue

- Then, grants user access to the service account and click on
Done.
Generating Account Keys
After the service have been successfully created, we can now generate credentials keys for the service account.
- On the
Service Accountspage, click on the three dotted icon beside the service account created and selectManage Keys.
- On the Keys page, click on the down arrow beside
ADD KEYand selectcreate new key.
- Select
JSONon the popped up and page and click oncreate.
- The file will be automatically downloaded to your local machine as shown below

- Note down the link to the file on your local machine as this will be required on your terraform config files. The newly created key will be listed on the
Keystab.
Enabling Appropriate API's on Project
In order to executes terraform scripts, we need to enable below API's;
- Cloud Resource Manager API.
- Cloud Billing API.
- Identity and Access Manager API.
To enable either of this, type the API name in the search box at the top of the page, select it in the search result and click Enable on the API page.


Terraform Files
Since our terraform is going to provision 2 Virtual Machines on GCP; one VM on private subnet and the other on public subnet, we will need to configure below listed files:
variables.tf: This file contains initialized
environment variablesfor accessing GCP.terraform.tfvars: It contains configuration for mapping variables to their values.
provider.tf - It contains configuration for GCP credentials.
network.tf: This file contains configuration for provisioning a
virtual private cloudnetwork with1 private subnetand1 public subnet,a public Internet protocol (IP) addressfor theNetwork Address Translation (NAT) serviceand theNat gateway.network-firewall.tf: This file contains configuration for provisioning the firewall rules on the networks. A
Firewallis a network security device that monitors incoming and outgoing network traffic and aFirewall Rulesare set of defined security rule that decides whether to allow or block specific traffic.vm.tf: This file contains configuration for provisioning
2 virtual machineson GCP.variables.tf
The variables.tf contains below code:
# define the GCP authentication file variable "gcp_auth_key" { type = string description = "GCP authentication file" } # define GCP project name variable "app_project" { type = string description = "GCP project name" } # define project name variable "app_name" { type = string description = "project name" } # define GCP region variable "gcp_region" { type = string description = "GCP region" } # define GCP zone variable "gcp_zone" { type = string description = "GCP zone" } # define private subnet variable "private_subnet" { type = string description = "private subnet CIDR 1" } # define public subnet variable "public_subnet" { type = string description = "public subnet CIDR 1" }The keyword
variableis used in initializing the variable, while values likegcp_auth_key,public subnet... represents thevariable name. The variable declaration block contains thetypekeyword which is used to specify thevariable typeand thedescriptionkey which describes the variable.terraform.tfvars
The terraform.tfvars contains the following code:
# GCP Settings app_project = "scacloud-311520" app_name = "finale" gcp_region = "us-central1" gcp_zone = "us-central1-a" gcp_auth_key = "credentials.json" # GCP Netwok private_subnet = "10.10.1.0/24" public_subnet = "10.10.0.0/24"This files contains the value to the variables declared in the variable.tf file. You should therefore fill in the appropriate value like swapping
scacloud-311520with yourproject-idon GCP. Thegcp_auth_keyspecify the path to theJSON Key Filepreviously download.provider.tf
The provider.tf contains:
provider "google" {
project = var.app_project
credentials = file("credentials.json")
region = var.gcp_region
zone = var.gcp_zone
}
The provider block specifies the web services you preferred; it can be aws (Amazon Web Services), azure, or as in this case google. The provider block contains the project which is used to specify the project-id on your web service, credentials gives the path where the JSON KEY FILE was saved, region indicates the region the resources provisioned will be placed and the zone also indicates the zone the resources are to be linked to.
network.tf
The network.tf file is configured as follow:
# create VPC
resource "google_compute_network" "vpc" {
name = "${var.app_name}-vpc"
auto_create_subnetworks = "false"
routing_mode = "GLOBAL"
}
# create private subnet
resource "google_compute_subnetwork" "private_subnet" {
provider = google
name = "${var.app_name}-private-subnet"
ip_cidr_range = var.private_subnet
network = google_compute_network.vpc.name
region = var.gcp_region
}
# create public subnet
resource "google_compute_subnetwork" "public_subnet" {
provider = google
name = "${var.app_name}-public-subnet"
ip_cidr_range = var.public_subnet
network = google_compute_network.vpc.name
region = var.gcp_region
}
# create a public ip for nat service
resource "google_compute_address" "nat-ip" {
name = "${var.app_name}-nap-ip"
project = var.app_project
region = var.gcp_region
}
# create a nat to allow private instances connect to internet
resource "google_compute_router" "nat-router" {
name = "${var.app_name}-nat-router"
network = google_compute_network.vpc.name
}
resource "google_compute_router_nat" "nat-gateway" {
name = "${var.app_name}-nat-gateway"
router = google_compute_router.nat-router.name
nat_ip_allocate_option = "MANUAL_ONLY"
nat_ips = [ google_compute_address.nat-ip.self_link ]
source_subnetwork_ip_ranges_to_nat = "ALL_SUBNETWORKS_ALL_IP_RANGES"
depends_on = [ google_compute_address.nat-ip ]
}
The resource key block is used to specify the type of google resources to be created. It follows the syntax the resource keyword, followed by the resource type and then the local to identify the resource.
The
google_compute_networkblock: This block create aVPC network. Thenamespecifies local name for the resources, you setauto_create_networktotrue; if you need the platform to autogenerates thesubnetsandfalseif otherwise and therouting_modeis set toGlobalin order to ensure thenetworkresouce is available on all regions.The
google_compute_subnetworkblock: This block creates asubnetworkon thevpcnetwork previously created. The first block creates aprivate subnetwhile the other creates apublic subnet. Theproviderkey specifies the cloud service, thenamekey specifies the name for the subnet on the platform, theip_cidr_rangespecifies theip addressrange of the subnet which can either beprivateorpublic, thenetworkkey indicates the network the subnet will be on and theregionspecifies the region the network will support.The
google_compute_addressblock: This block is used to create apublic IP(Internet Protocol) addressfor theNetwork Address Translation (NAT) service. Thenamekey indicates the name of theip address, theprojectkey specifies theproject-idof the project the address is to be linked to, andregionkey specifies the region theip addresssupport.The
google_compute_routerblock: this block is used to create arouterthat allowprivate instancesto connect to the internet. Thenamekey specifies the name ofrouterand thenetworkkey indicates thenetworkthe router routes on.The
google_compute_router_natblock: This block is used to create a network gateway for the network. It allows data to flow from one discrete network to another. Thenamekey indicates the name of theNAT router, therouterkey indicates therouterthe gateway in connected to, thenat_ip_allocate_optionis set toMANUAL_ONLYin order to ensure that you create and manually assign static (reserved) regional external IP addresses to your Cloud NAT gateway, thenat_ipskey specifies theip addressof theNAT gateway, thesource_subnetwork_ip_ranges_to_natis set toALL_SUBNETWORKS_ALL_IP_RANGESto ensure your all of theIP rangesin everySubnetworkare allowed to Nat, and thedepends_onkey indicates theIP Addressthe gateway depends on.
network-firewall.tf
The network-firewall.tf contains:
# allow http traffic
resource "google_compute_firewall" "allow-http" {
name = "${var.app_name}-fw-allow-http"
network = "${google_compute_network.vpc.name}"
allow {
protocol = "tcp"
ports = ["80"]
}
target_tags = ["http"]
}
# allow https traffic
resource "google_compute_firewall" "allow-https" {
name = "${var.app_name}-fw-allow-https"
network = "${google_compute_network.vpc.name}"
allow {
protocol = "tcp"
ports = ["443"]
}
target_tags = ["https"]
}
# allow ssh traffic
resource "google_compute_firewall" "allow-ssh" {
name = "${var.app_name}-fw-allow-ssh"
network = "${google_compute_network.vpc.name}"
allow {
protocol = "tcp"
ports = ["22"]
}
target_tags = ["ssh"]
}
# allow rdp traffic
resource "google_compute_firewall" "allow-rdp" {
name = "${var.app_name}-fw-allow-rdp"
network = "${google_compute_network.vpc.name}"
allow {
protocol = "tcp"
ports = ["3389"]
}
target_tags = ["rdp"]
}
The resource key block is used to specify the type of google resources to be created. It follows the syntax the resource keyword, followed by the resource type and then the local name to identify the firewall rules. Here allow-http, allow-https and allow-ssh firewall rules are applied. The name key specifies the firewall name, the network key indicates the network the firewall rule is been applied on, the allow key indicates the http protocol name and port it run on, and the target-tags key indicates tags the firewall rule is given.
vm.tf
The vm.tf files contains the following configuration:
# Create VM instances on private subnet
resource "google_compute_instance" "vm_instance_private" {
name = "${var.app_name}-vm_private"
machine_type = "f1-micro"
zone = var.gcp_zone
hostname = "${var.app_name}-vm_private.${var.app_project}"
tags = ["ssh","http"]
boot_disk {
initialize_params {
image = "ubuntu-os-cloud/ubuntu-2004-lts"
}
}
network_interface {
network = google_compute_network.vpc.name
subnetwork = google_compute_subnetwork.private_subnet.name
}
}
# Create VM instances on public subnet
resource "google_compute_instance" "vm_instance_public" {
name = "${var.app_name}-vm_public"
machine_type = "f1-micro"
zone = var.gcp_zone
hostname = "${var.app_name}vm_public.${var.app_project}"
tags = ["ssh","http"]
boot_disk {
initialize_params {
image = "ubuntu-os-cloud/ubuntu-2004-lts"
}
}
network_interface {
network = google_compute_network.vpc.name
subnetwork = google_compute_subnetwork.public_subnet.name
access_config {
}
}
The resource key block is used to specify the type of google resources to be created. It follows the syntax the resource keyword, followed by the resource type and then the local name to identify the vm instances. The name key indicates the name of the VM, the machine-type key is used to set of virtualized hardware resources available to a virtual machine (VM) instance, including the system memory size, virtual CPU (vCPU) count, and persistent disk limits, the zone key sets the zone the VM is attached to, the hostname key indicates the name given to the VM on the network that is used to identify the VM on the internet, and the tags key indicates the firewall rule/s to apply on the instances.
The
boot_diskblock indicates theOperating systemof the VM, which is always a container image.The
network_interfaceblock indicates thenetworkthe VM is connected to, thesubnetworkwhich can either be theprivateorpublicsubnetwork created in the network.tf file, and theaccess_configblock indicates the external ip of the VM; You should omit this block if the VM is to be on a private subnet, but for public , ensure it is included. if left empty, it is automatically generated.
Executing terraform files
After your terraform files have been created; then use below commands to executes them.
Note: All files are to be arranged in a folder.
terraform init
The terraform init command is used to initialize a working directory containing Terraform configuration files. This is the first command that should be run after writing a new Terraform configuration or cloning an existing one from version control. It is safe to run this command multiple times.
terraform plan
The terraform plan command is used to create an execution plan. Terraform performs a refresh, unless explicitly disabled, and then determines what actions are necessary to achieve the desired state specified in the configuration files.
terraform apply
The terraform apply command is used to apply the changes required to reach the desired state of the configuration, or the pre-determined set of actions generated by a terraform plan execution plan.
..................................................................................................................................
And that's how to provision Virtual Machines on private and public subnetwork on a network, feel free to comment, correct , and notify for any clarification.
