DEV Community

Shaikh Al Amin
Shaikh Al Amin

Posted on

Build Production-Ready GCP Infrastructure from Scratch Part 01

Build Production-Ready GCP Infrastructure from Scratch: A Complete Console Guide

A 4-Part Series for Complete Beginners


Table of Contents


Part 1: Foundation - Project Setup, VPC & Networking

Overview

In this first part of our series, you'll build the networking foundation for a production-ready GCP infrastructure. We'll create a custom VPC with 5 subnets, configure Cloud NAT for internet access, set up service accounts, and implement service account-targeted firewall rules.

What you'll build:

  • Custom VPC (10.0.0.0/16) in europe-west1 region
  • 5 subnets for different application tiers
  • Cloud NAT Gateway for outbound internet access
  • 4 Service Accounts for IAM-based security
  • Firewall rules with service account targeting

Estimated time: 45-60 minutes

Estimated cost: ~$32/month (Cloud NAT only)


Prerequisites

Before we begin, ensure you have:

  1. GCP Account - Sign up at console.cloud.google.com
  2. Billing Account - Required for creating resources
  3. Free Tier Credit - New accounts get $300 credit for 90 days
  4. Required Permissions - Project Owner or Editor role

Cost Alert: This tutorial will incur charges. With the free tier credit, you can follow along for free. After that, expect ~$350/month total for all infrastructure.

Why GCP for Your Infrastructure?

  • EU Data Residency - Host in europe-west1 (Belgium) for compliance
  • Private Network - No public IPs needed for database and application servers
  • Managed Services - Focus on code, not infrastructure management
  • Built-in Security - IAM-based access control, VPC Service Controls

Step 1: Create or Select GCP Project

Navigation Path

  1. Go to console.cloud.google.com
  2. Click the project dropdown at the top (next to "Google Cloud Platform")
  3. Click "New Project"

Screenshot: GCP Console Homepage

Project Configuration

Fill in the form:

Field Value Notes
Project name My GCP Infrastructure Display name
Project ID my-gcp-project-id Must be globally unique
Organization (Your organization) Leave blank for personal
Location No organization For personal projects

Pro Tip: Project IDs cannot be changed after creation. Choose carefully and avoid spaces.

Screenshot: Create Project Form

Click "Create" and wait 1-2 minutes for project creation.

Verify Project Creation

You should see a notification: "Project 'My GCP Infrastructure' is ready."

Click "Select project" to switch to your new project.

Enable Required APIs

Some resources require specific APIs to be enabled:

  1. Navigate to APIs & ServicesLibrary
  2. Search for and enable these APIs:
    • Compute Engine API
    • Cloud SQL API
    • Secret Manager API
    • Identity-Aware Proxy API

Screenshot: Enable APIs

Why: Enabling APIs early prevents "API not enabled" errors during resource creation.


Step 2: Create Custom VPC (10.0.0.0/16)

What is a VPC?

A Virtual Private Cloud (VPC) is your isolated network in Google Cloud. Think of it as your own data center network in the cloud.

Navigation Path

  1. From the main menu (hamburger icon ≡), navigate to: NetworkingVPC networks

Screenshot: VPC Networks Navigation

  1. Click "Create VPC network"

VPC Configuration

Screenshot: VPC Creation Form

Fill in the form:

Field Value Notes
Name dev-network Environment-prefixed for clarity
Description Development environment VPC Optional but recommended
Custom VPC creation Enable CRITICAL: Uncheck "Automatic subnet creation"
Routing mode Regional Recommended for most cases
MTU 1460 Default (leave unchanged)

VPC Flow Logs Configuration

Scroll down to "VPC flow logs" section:

Field Value Notes
Off/On On Enable for security monitoring
Sampling 50% Balance cost vs visibility
Aggregation interval 5 sec Most granular option
Metadata Include all Full logging for forensics

Cost Alert: VPC Flow Logs cost ~$0.005/GB. With 50% sampling, expect ~$5-10/month for moderate traffic.

Why Flow Logs: Essential for troubleshooting network issues and security audits. They show all traffic flows through your VPC.

Dynamic Routing Mode

Leave as "Regional" (default).

Create the VPC

Click "Create" at the bottom.

Wait 30-60 seconds for creation. You should see:

VPC network "dev-network" was created successfully.
Enter fullscreen mode Exit fullscreen mode

Verify VPC Creation

You should see dev-network in your VPC networks list with:

  • Subnets: 0 (we'll add these next)
  • Routing mode: Regional
  • Flow logs: On

Step 3: Create 5 Subnets (Sequential /24)

What are Subnets?

Subnets divide your VPC into smaller networks. Each subnet hosts a specific tier of your application:

  • Public subnet (load balancer, bastion)
  • Private subnets (backend, database, cache, observability)

Why europe-west1?

We're using europe-west1 (Belgium) for:

  • EU Data Residency - Data stays within Europe
  • Low Latency - Good for European users
  • Cost - Competitive pricing compared to other regions

Pro Tip: For production, consider multi-region deployment for disaster recovery.

Subnet Overview

Subnet Name CIDR Purpose
public-subnet 10.0.1.0/24 Bastion, Load Balancer
private-backend 10.0.2.0/24 Backend VMs (NestJS app)
private-data 10.0.3.0/24 Cloud SQL PostgreSQL
private-cache 10.0.4.0/24 Redis + PgBouncer
private-obs 10.0.5.0/24 Prometheus, Loki, Grafana

Why /24: Provides 251 usable IP addresses per subnet (sufficient for most applications).

Create Each Subnet

We'll create all 5 subnets. The process is identical for each, just with different values.

Subnet 1: public-subnet (10.0.1.0/24)

  1. Click on dev-network in your VPC list
  2. Click the "SUBNETS" tab
  3. Click "Create subnet"

Screenshot: Create Subnet

Fill in the form:

Field Value Notes
Name public-subnet Descriptive name
Description Public subnet for bastion and load balancer Documentation
Region europe-west1 Belgium
IP address range 10.0.1.0/24 Manual CIDR
Private Google Access Enable CRITICAL - see below

CRITICAL - Private Google Access: This allows VMs without public IPs to reach Google services (Cloud SQL, Secret Manager, etc.). Without this, private VMs cannot access GCP services!

Flow Logs for Subnet 1

Scroll down to "Flow logs" section:

Field Value Notes
Off/On On Same as VPC
Sampling 50% Consistent with VPC
Aggregation interval 5 sec Consistent with VPC
Metadata Include all Consistent with VPC

Click "Add" to create the subnet.

Subnet 2: private-backend (10.0.2.0/24)

Repeat the process with these values:

Field Value
Name private-backend
Region europe-west1
IP address range 10.0.2.0/24
Private Google Access Enable
Flow logs On (same settings)

Subnet 3: private-data (10.0.3.0/24)

Field Value
Name private-data
Region europe-west1
IP address range 10.0.3.0/24
Private Google Access Enable
Flow logs On

Why separate subnet: Isolates database layer for security. Database VMs have different firewall rules than backend VMs.

Subnet 4: private-cache (10.0.4.0/24)

Field Value
Name private-cache
Region europe-west1
IP address range 10.0.4.0/24
Private Google Access Enable
Flow logs On

Subnet 5: private-obs (10.0.5.0/24)

Field Value
Name private-obs
Region europe-west1
IP address range 10.0.5.0/24
Private Google Access Enable
Flow logs On

Verify All Subnets

You should now see 5 subnets under dev-network:

Subnet Region CIDR Private IP Access Flow Logs
public-subnet europe-west1 10.0.1.0/24 On On
private-backend europe-west1 10.0.2.0/24 On On
private-data europe-west1 10.0.3.0/24 On On
private-cache europe-west1 10.0.4.0/24 On On
private-obs europe-west1 10.0.5.0/24 On On

Step 4: Create Cloud Router

What is a Cloud Router?

Cloud Router manages dynamic routing for your Cloud NAT Gateway. It's required for NAT functionality.

Navigation Path

  1. Navigate to Hybrid ConnectivityCloud Routers
  2. Click "Create Router"

Screenshot: Cloud Router Creation

Router Configuration

Field Value Notes
Name dev-nat-router Descriptive name
Network dev-network Our VPC
Region europe-west1 Same as subnets
Google ASN 65000 Default (leave unchanged)

Why ASN: Autonomous System Number uniquely identifies your router. 65000 is the default for private networks.

Click "Create" and wait for creation (should be instant).


Step 5: Create Cloud NAT Gateway

What is Cloud NAT?

Cloud NAT allows VMs without public IPs to access the internet. This is essential for:

  • Downloading packages (apt, npm)
  • Calling external APIs
  • Software updates

Navigation Path

  1. Navigate to Network ServicesCloud NAT
  2. Click "Get started" or "Create Cloud NAT Gateway"

Screenshot: Cloud NAT Creation

Gateway Configuration

Basic Settings

Field Value Notes
Gateway name dev-nat-gateway Descriptive
Cloud Router dev-nat-router Router we created
Region europe-west1 Same region

NAT Mapping (Critical Section)

Screenshot: NAT Mapping Configuration

Field Value Notes
Custom single region NAT Select For single region
Cloud Router dev-nat-router Already populated
Source subnetworks ✓ Select all 5 subnets All subnets need internet
NAT IP allocation Manual Critical for HA

Why Manual IP Allocation: Gives us control over outbound IPs. We'll create 2 IPs for high availability.

NAT IP Allocation

Click "Add reserved IPs" twice:

IP 1:
| Field | Value |
|-------|-------|
| Name | dev-nat-ip-1 |
| Static IP address | (Leave blank - auto-allocate) |

IP 2:
| Field | Value |
|-------|-------|
| Name | dev-nat-ip-2 |
| Static IP address | (Leave blank - auto-allocate) |

Why 2 IPs: High availability. If one IP fails, the other handles traffic.

Cost Alert: ~$0.045/hr per NAT gateway = ~$32/month. Static IPs are free when attached to NAT.

Logging

Leave "Log and monitor" disabled (not needed for NAT).

Create the NAT Gateway

Click "Create" and wait 1-2 minutes.

Verify Cloud NAT

You should see:

  • Status: Running
  • Cloud Router: dev-nat-router
  • External IPs: 2 IPs assigned
  • Subnets: All 5 subnets mapped

Step 6: Create Service Accounts

What are Service Accounts?

Service accounts are identities for applications (not humans). They allow VMs to authenticate with Google Cloud services.

Why Service Account Targeting?

Security Best Practice: Instead of using network tags (which can be spoofed), we use service accounts to target firewall rules. This provides IAM-based security.

Why SA-targeted is more secure: If someone compromises your VM, they can't change network tags to bypass firewall rules. Service account targeting is enforced at the IAM level.

Create Service Accounts

We'll create 4 service accounts for different tiers.

Service Account 1: Backend SA

  1. Navigate to IAM & AdminService Accounts
  2. Click "Create Service Account"

Screenshot: Create Service Account

Fill in the form:

Field Value Notes
Service account name backend-dev-sa Tier-environment pattern
Service account description Service account for backend VMs Documentation
Service account ID (Auto-filled) backend-dev-sa@PROJECT_ID.iam

Click "Create and continue".

Skip the "Grant this service account access to project" step (we'll add roles later).

Click "Done".

Service Account 2: Cache SA

Repeat the process:

Field Value
Name cache-dev-sa
Description Service account for Redis/PgBouncer VM

Service Account 3: Observability SA

Field Value
Name observability-dev-sa
Description Service account for monitoring tools

Service Account 4: Bastion SA

Field Value
Name bastion-dev-sa
Description Service account for bastion host

Add IAM Roles to Service Accounts

Now we'll add roles to allow VMs to write logs and metrics.

For Backend, Cache, and Observability SAs:

  1. Click on the service account (e.g., backend-dev-sa)
  2. Click the "Permissions" tab
  3. Click "Grant access"

Add these roles:

Role Purpose
Logs Writer Allow VMs to write to Cloud Logging
Monitoring Metric Writer Allow VMs to send metrics to Cloud Monitoring

Screenshot: Add IAM Roles

Add Principal: backend-dev-sa@PROJECT_ID.iam.gserviceaccount.com

Select Role: Logs WriterMonitoring Metric Writer

Repeat for cache-dev-sa and observability-dev-sa.

For Bastion SA:

Bastion only needs Logs Writer role.


Step 7: Create Firewall Rules (Service Account Targeted)

Firewall Rule Priority

GCP evaluates firewall rules by priority number:

  • Lower numbers = Higher priority (evaluated first)
  • Deny rules typically use priority 500
  • Allow rules typically use priority 1000+

Screenshot: Firewall Priority

Why this order: Deny rules (higher priority) are evaluated before allow rules. This ensures we can block specific traffic before allowing general traffic.

Rule 1: Deny SMTP Egress (Priority 500)

Purpose: Prevent compromised VMs from sending spam.

  1. Navigate to VPC networksFirewall
  2. Click "Create firewall rule"

Fill in the form:

Field Value Notes
Name dev-firewall-deny-smtp-egress Descriptive
Network dev-network Our VPC
Priority 500 High priority (deny)
Direction of traffic Egress Outbound
Action on match Deny Block traffic
Target service accounts Select all 4 SAs Apply to all private VMs

Screenshot: Firewall Rule Deny SMTP

Filters section:
| Field | Value |
|-------|-------|
| Destination filter | IPv4 range |
| IPv4 range | 0.0.0.0/0 | All destinations |

Protocols and ports:
| Field | Value |
|-------|-------|
| Allow protocols | Specified protocols and ports |
| TCP | ✓ Checked |
| Ports | 25 | SMTP port |

Logging:
| Field | Value |
|-------|-------|
| Log config | On | Enable for security |
| Metadata | Include all | Full logging |

Click "Create".

Why log deny rules: Detect potential compromise. If a VM tries to send SMTP traffic, it's suspicious.

Rule 2: Allow SSH to Backend (Priority 1000)

Purpose: Allow SSH access to backend VMs for troubleshooting.

Field Value
Name dev-firewall-allow-ssh-backend
Network dev-network
Priority 1000
Direction Ingress
Action Allow
Target service accounts backend-dev-sa

Source filter:
| Field | Value |
|-------|-------|
| Source IPv4 ranges | 0.0.0.0/0 | All sources (restrict in prod!) |

Security Warning: In production, restrict SSH to specific IPs or VPN ranges.

Protocols and ports:
| Field | Value |
|-------|-------|
| TCP | ✓ Checked |
| Ports | 22 | SSH |

Logging:
| Field | Value |
|-------|-------|
| Log config | On | Critical - log SSH access |
| Metadata | Include all | Full metadata |

Click "Create".

Rule 3: Allow Internal HTTP (Priority 1001)

Purpose: Allow internal HTTP/HTTPS traffic between services (load balancer → backend).

Field Value
Name dev-firewall-allow-http-backend
Network dev-network
Priority 1001
Direction Ingress
Action Allow
Target service accounts backend-dev-sa

Source filter:
| Field | Value |
|-------|-------|
| Source IPv4 ranges | 10.0.0.0/8 | Internal VPC traffic only |

Why 10.0.0.0/8: Covers all our subnets (10.0.1.0-10.0.5.0). More secure than 0.0.0.0/0.

Protocols and ports:
| Field | Value |
|-------|-------|
| TCP | ✓ Checked |
| Ports | 80, 443 | HTTP and HTTPS |

Logging:
| Field | Value |
|-------|-------|
| Log config | Off | Too noisy for production |

Click "Create".

Rule 4: Allow Health Checks (Priority 1002)

Purpose: Allow GCP health checkers to probe backend VMs.

Field Value
Name dev-firewall-allow-health-checks
Network dev-network
Priority 1002
Direction Ingress
Action Allow
Target service accounts backend-dev-sa

Source filter:
| Field | Value |
|-------|-------|
| Source IPv4 ranges | 35.191.0.0/16, 130.211.0.0/22 | GCP health check ranges |

Why these IPs: These are GCP's health checker IP ranges. Without this rule, health checks fail and load balancer won't route traffic.

Protocols and ports:
| Field | Value |
|-------|-------|
| TCP | ✓ Checked |
| Ports | 80, 443 | HTTP and HTTPS |

Logging:
| Field | Value |
|-------|-------|
| Log config | Off | Health checks are too noisy |

Click "Create".

Rule 5: Allow Backend to Cache (Priority 1003)

Purpose: Allow backend VMs to connect to Redis (6379) and PgBouncer (6432).

Field Value
Name dev-allow-backend-to-cache
Network dev-network
Priority 1003
Direction Ingress
Action Allow
Source service accounts backend-dev-sa
Target service accounts cache-dev-sa

Service Account Source: This is the key to SA-targeted firewall. We're allowing traffic FROM backend SA TO cache SA.

Protocols and ports:
| Field | Value |
|-------|-------|
| TCP | ✓ Checked |
| Ports | 6379, 6432 | Redis and PgBouncer |

Logging:
| Field | Value |
|-------|-------|
| Log config | On | Useful for debugging |

Click "Create".

Verify All Firewall Rules

You should see 5 firewall rules:

Rule Name Priority Direction Action Target
dev-firewall-deny-smtp-egress 500 Egress Deny All SAs
dev-firewall-allow-ssh-backend 1000 Ingress Allow backend-dev-sa
dev-firewall-allow-http-backend 1001 Ingress Allow backend-dev-sa
dev-firewall-allow-health-checks 1002 Ingress Allow backend-dev-sa
dev-allow-backend-to-cache 1003 Ingress Allow cache-dev-sa

Part 1 Verification Checklist

Before moving to Part 2, verify:

  • [ ] VPC dev-network exists in europe-west1
  • [ ] 5 subnets created with correct CIDRs (10.0.1.0/24 - 10.0.5.0/24)
  • [ ] Private Google Access enabled on all subnets
  • [ ] Cloud NAT dev-nat-gateway has 2 external IPs
  • [ ] Cloud Router dev-nat-router status is "Ready"
  • [ ] 4 service accounts created (backend, cache, observability, bastion)
  • [ ] Service accounts have Logs Writer role
  • [ ] All 5 firewall rules visible in VPC → Firewall

Screenshot: Completed Part 1


Cost Summary - Part 1

Component Monthly Cost Notes
Cloud NAT Gateway ~$32 2 static IPs + NAT gateway fee
VPC Flow Logs ~$5-10 Depends on traffic volume
Total Part 1 ~$37-42 ~$42/month

Cost Optimization: In production, consider:

  • Reducing Flow Logs sampling to 25%
  • Using 1 NAT IP instead of 2 (lower HA)
  • Disabling Flow Logs on non-critical subnets

Troubleshooting - Part 1

Issue: VPC Creation Fails

Symptom: "API not enabled" error

Solution:

  1. Navigate to APIs & Services → Dashboard
  2. Search for "Compute Engine API"
  3. Click "Enable"

Issue: Subnet Creation Fails

Symptom: "IP range overlaps with existing subnet"

Solution:

  1. Check existing subnet CIDRs in VPC details
  2. Ensure each subnet has unique /24 range
  3. Verify you're using 10.0.1.0 through 10.0.5.0 (not overlapping)

Issue: Cloud NAT Shows "Failed"

Symptom: NAT gateway status is "Failed"

Solution:

  1. Verify Cloud Router exists and is in same region
  2. Check NAT IP allocation (should show 2 IPs)
  3. Ensure subnets have no external IP (Cloud NAT only for private IPs)

Issue: Firewall Rule Not Working

Symptom: Traffic blocked unexpectedly

Solution:

  1. Check rule priority (lower = higher priority)
  2. Verify service account email matches exactly
  3. Check implicit deny: If no rule allows, traffic is blocked by default

What's Next - Part 2?

In Part 2: Security Services, you'll build:

  • Secret Manager for secure credential storage
  • Bastion host with IAP tunneling for secure SSH
  • IAM permissions for access control
  • OS Login for keyless SSH authentication

Continue to Part 2: Security Services →


References


Foundational Infrastructure Complete! Your VPC, subnets, NAT gateway, service accounts, and firewall rules are ready. Next, we'll add security services (Secrets, Bastion, IAM).

Top comments (0)