LAB01_GCP_Compute Engine: Deploying a VM with Firewall Rules

Compute Engine: Deploying a VM with Firewall Rules

☁ GCP 🟢 Beginner Compute Engine Firewall Network Tags

Scenario

You are deploying a simple Nginx web server on Google Cloud Platform. You need to provision a Compute Engine virtual machine (VM) and ensure it's accessible from the internet on port 80. In GCP, firewall rules are applied to VMs using Network Tags rather than Security Groups.

Your Objectives
  • Create a google_compute_instance running a Debian 11 image (minimum e2-micro machine type).
  • Assign a network tag (e.g., web-server) to the instance.
  • Use a metadata_startup_script to install and start Nginx.
  • Create a google_compute_firewall rule that allows ingress on TCP port 80 for instances with that target tag, sourced from 0.0.0.0/0.
  • Output the public IP address of the instance.

Additional Context

Unlike AWS where Security Groups are attached to instances via ID, GCP uses Network Tags. You tag an instance (e.g., allow-http), and then create a firewall rule targeting that tag (target_tags = ["allow-http"]).

GCP's default network creates subnets in every region automatically. If you don't specify a network/subnet in Terraform, it attaches the VM to the `default` network in the provider's region.

variables.tf

variable "project_id" { type = string; description = "Your GCP Project ID" }
variable "gcp_region" { type = string; default = "us-central1" }
variable "gcp_zone"   { type = string; default = "us-central1-a" }

main.tf

provider "google" {
  project = var.project_id
  region  = var.gcp_region
  zone    = var.gcp_zone
}

# The Compute Engine Instance
resource "google_compute_instance" "web" {
  name         = "nginx-web-server"
  machine_type = "e2-micro"

  # Network tags map this instance to firewall rules
  tags = ["web-server"]

  boot_disk {
    initialize_params {
      image = "debian-cloud/debian-11"
    }
  }

  network_interface {
    network = "default"
    # An empty access_config block assigns an ephemeral public IP
    access_config {}
  }

  metadata_startup_script = <<-EOF
    #!/bin/bash
    apt-get update
    apt-get install -y nginx
    systemctl enable nginx
    systemctl start nginx
    echo "

Deployed via Terraform on GCP

" > /var/www/html/index.html EOF labels = { environment = "dev" managed_by = "terraform" } } # The Firewall Rule resource "google_compute_firewall" "allow_http" { name = "allow-http-ingress" network = "default" allow { protocol = "tcp" ports = ["80"] } # Apply this rule to any instance with this tag target_tags = ["web-server"] # Allow traffic from anywhere source_ranges = ["0.0.0.0/0"] }

outputs.tf

output "instance_public_ip" {
  value       = google_compute_instance.web.network_interface[0].access_config[0].nat_ip
  description = "The public IP address of the web server"
}

Workflow Commands

terraform init
terraform apply -var="project_id=my-gcp-project-123"

# Curl the public IP to verify Nginx is running
curl http://$(terraform output -raw instance_public_ip)

terraform destroy -var="project_id=my-gcp-project-123"
✓ Expected Output After Apply
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

Outputs:

instance_public_ip = "34.122.xxx.xxx"