Skip to main content

Command Palette

Search for a command to run...

Provisioning Vm's on private and public subnet in GCP

Infrastructure as code with terraform

Updated
12 min read
Provisioning Vm's on private and public subnet in GCP

Prerequisites

  • GCP account
  • Linux Operating System (Preferably Ubuntu 20.04LTS or WSL on Windows)

What you will learn

Installing Terraform

Use the commands below to install terraform on your operating system.

sudo apt update
  • Run update command 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 wget command to download the terraform files from the releases repository. This command executes to download terraform version 0.14.3 in zip format. You might need to install wget if terminal output is wget command not found; use below command to install wget.
sudo apt install wget
  • After successfully installing wget if 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 -y install 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 your bin folder. The bin folder contains all executables filesrequired for minimal system working. Use below command to move the unzipped files.
sudo mv terraform /usr/local/bin/
  • After using the mv command 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 Resources and on the search results highlighted in circles as shown below.

managedresources.JPG

  • Then, click on create project as circled.

createproject.JPG

  • 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

nameandcreate.JPG

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

projectcreated.JPG

Creating Service Account with Appropriates Roles and Permissions

  • After the project have been created, navigate to IAM & Admin and select Service Accounts as shown below

navtosa.JPG

  • On the service account page, select CREATE SERVICE ACCOUNT and ensure the service account is created in the preferred project. createsa.JPG
  • On the new page, you have been redirected to, fill in the service account name and description of the service account; then click CREATE. fillsa.JPG

  • 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

arsa.JPG

  • Then, grants user access to the service account and click on Done. grantusa.JPG

Generating Account Keys

After the service have been successfully created, we can now generate credentials keys for the service account.

  • On the Service Accounts page, click on the three dotted icon beside the service account created and select Manage Keys. managekeys.JPG
  • On the Keys page, click on the down arrow beside ADD KEY and select create new key. addkey.JPG
  • Select JSON on the popped up and page and click on create. jsoncreae.JPG
  • The file will be automatically downloaded to your local machine as shown below autodownload.JPG
  • 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 Keys tab. newkeyadd.JPG

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.

cbapisearch.JPG

cbenable.JPG

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 variables for 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 cloud network with 1 private subnet and 1 public subnet, a public Internet protocol (IP) address for the Network Address Translation (NAT) service and the Nat gateway.

  • network-firewall.tf: This file contains configuration for provisioning the firewall rules on the networks. A Firewall is a network security device that monitors incoming and outgoing network traffic and a Firewall Rules are set of defined security rule that decides whether to allow or block specific traffic.

  • vm.tf: This file contains configuration for provisioning 2 virtual machines on 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 variable is used in initializing the variable, while values like gcp_auth_key, public subnet... represents the variable name. The variable declaration block contains the type keyword which is used to specify the variable type and the description key 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-311520 with your project-id on GCP. The gcp_auth_key specify the path to the JSON Key File previously 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_network block: This block create a VPC network. The name specifies local name for the resources, you set auto_create_network to true; if you need the platform to autogenerates the subnets and false if otherwise and therouting_mode is set to Global in order to ensure the network resouce is available on all regions.

The google_compute_subnetwork block: This block creates a subnetwork on the vpc network previously created. The first block creates a private subnet while the other creates a public subnet. The provider key specifies the cloud service, the name key specifies the name for the subnet on the platform, the ip_cidr_range specifies the ip address range of the subnet which can either be private or public, the network key indicates the network the subnet will be on and the region specifies the region the network will support.

The google_compute_address block: This block is used to create a public IP(Internet Protocol) address for the Network Address Translation (NAT) service. The name key indicates the name of the ip address, the project key specifies the project-id of the project the address is to be linked to, and region key specifies the region the ip address support.

The google_compute_router block: this block is used to create a router that allow private instances to connect to the internet. The name key specifies the name of router and the network key indicates the network the router routes on.

The google_compute_router_nat block: This block is used to create a network gateway for the network. It allows data to flow from one discrete network to another. The name key indicates the name of the NAT router, the router key indicates the router the gateway in connected to, the nat_ip_allocate_option is set to MANUAL_ONLY in order to ensure that you create and manually assign static (reserved) regional external IP addresses to your Cloud NAT gateway, the nat_ips key specifies the ip address of the NAT gateway, the source_subnetwork_ip_ranges_to_nat is set to ALL_SUBNETWORKS_ALL_IP_RANGES to ensure your all of the IP ranges in every Subnetwork are allowed to Nat, and the depends_on key indicates the IP Address the 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_disk block indicates the Operating system of the VM, which is always a container image.

The network_interface block indicates the network the VM is connected to, the subnetwork which can either be the private or public subnetwork created in the network.tf file, and the access_config block 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.