From AWS to GCP: Mental Models and Architecture Mapping for DevOps Engineers

When DevOps engineers familiar with AWS first encounter Google Cloud Platform (GCP), the biggest friction rarely comes from terminology mapping—it stems from conflicting underlying architectural assumptions.

While both platforms provide virtual machines, managed containers, object storage, and identity management, their foundational mental models differ sharply across resource boundaries, permission inheritance, and network topology. Applying AWS operational instincts directly to GCP not only risks unintended permission overwrites in Terraform, but can also lead to misjudgments in network planning and Kubernetes integration.


Core Architecture Mapping Overview

Before diving into specific mechanisms, the table below highlights the architectural dimensions with the highest “cognitive friction” in day-to-day DevOps operations:

DomainAWS ConceptGCP ConceptDifference LevelKey Mindset Shift
Resource IsolationAWS Organizations / AccountOrganization / Folder / ProjectHighA Project is a trust boundary and billing unit, not an independent account
Identity & AccessIAM User / Role / PolicyIAM Principal / Role / Allow PolicyHighPermissions attach to the resource hierarchy and inherit downward; a Role is merely a set of permissions
Virtual NetworkingVPC (Regional)VPC (Global, Subnets are Regional)HighA single VPC spans the globe; cross-region routing requires no peering
FirewallsSecurity Group + NACLVPC Firewall Rules / PoliciesMediumSingle-tier stateful firewall supporting Allow/Deny and Priority
Private ConnectivityVPC Endpoint / PrivateLinkPrivate Google Access / Private Service Connect / Private Services AccessMediumSplit across three distinct mechanisms; access to Google APIs is free
Outbound NATNAT Gateway (traditionally one per AZ)Cloud NATMediumSoftware-defined distributed architecture attached to Cloud Router
Load BalancingALB / NLB (Regional resources)Cloud Load BalancingMediumGlobal Anycast single-IP ingress composed of modular resources
Container OrchestrationAmazon EKSGoogle Kubernetes Engine (GKE)MediumBuilt-in rolling auto-upgrades, VPC-native networking, and Autopilot
Serverless ContainersECS on Fargate / App RunnerCloud RunMediumSingle platform unifying HTTP services, scheduled jobs, and worker pools
Audit LoggingAWS CloudTrailCloud Audit LogsMediumAdmin logs are mandatory and free; Data Access logs are disabled by default

1. Resource Hierarchy and IAM: The Downward-Inheriting Union Model

A Project Is Not an AWS Account

In AWS, the fundamental isolation boundary is the AWS Account. AWS Organizations groups accounts using Organizational Units (OUs) and restricts maximum allowable permissions from the top down using Service Control Policies (SCPs), but each account maintains an independent IAM system.

GCP, by contrast, enforces a strict tree-like structure: the Resource Hierarchy governs the relationship of Organization → Folder → Project → Underlying Resources.

 AWS Model:
 [Organization] --> [OU] --> [AWS Account]
                               +-- Role / User / Resources

 GCP Model:
 [Organization]
   +-- [Folder]
         +-- [Project] (Resource Container & Billing Unit)
               +-- Compute Engine / GKE / Cloud Storage

In GCP, a Project is the container for billing, quotas, enabled APIs, and default networking. The core distinction lies in how permissions flow:

Service Accounts vs. IAM Roles

In AWS, an IAM Role acts like a “hat”: an EC2 instance wears it via an Instance Profile, a Lambda function wears it via an Execution Role, and a developer wears it via AssumeRole.

GCP completely decouples identity from permissions into two distinct primitives:

  1. Role: A pure collection of permissions (e.g., roles/storage.objectViewer). A Role is not an identity and cannot be “assumed.”
  2. Service Account (SA): A machine identity with an email address format (e.g., deployer@PROJECT_ID.iam.gserviceaccount.com).

The fundamental architectural differences between the two are outlined below:

DimensionAWS IAM RoleGCP Service Account
Fundamental NatureVirtual identity (assumed by entities)Machine identity (has a dedicated email)
Permission AssignmentIAM Policies attached directlyRoles (permission sets) granted on the resource hierarchy
Compute BindingInstance Profile / Execution RoleAttached directly to VMs, GKE nodes, or Cloud Run
Resource StatusPure identity constructBoth an identity and a resource (requires authorization to use)

WARNING

Two-tier authorization blind spot: In GCP, a Service Account is itself a resource. To run a compute workload (or allow a user) as a specific SA, the operator must hold the roles/iam.serviceAccountUser role on that SA. Having permission to deploy resources does not inherently grant permission to act as a given Service Account.

In production operations, follow these two best practices:

Terraform IAM Pitfalls and Local Authentication

In AWS Terraform, aws_iam_role_policy_attachment manages only the association between a specific policy and a role, leaving other existing bindings untouched. In contrast, the GCP Provider offers three distinct IAM resource types with varying levels of granularity (see google_project_iam), each with vastly different behaviors and blast radii:

# 1. google_project_iam_binding (Authoritative over a single role)
# Controls the exclusive member list for a given role. If someone manually adds a member via the Console, the next `terraform apply` will purge them!
resource "google_project_iam_binding" "editor_binding" {
  project = var.project_id
  role    = "roles/editor"
  members = ["serviceAccount:${google_service_account.admin.email}"]
}

# 2. google_project_iam_member (Safest: Additive)
# Adds a single binding without affecting other members under this role or out-of-band Console configurations.
resource "google_project_iam_member" "deployer_ar_writer" {
  project = var.project_id
  role    = "roles/artifactregistry.writer"
  member  = "serviceAccount:${google_service_account.deployer.email}"
}

When writing IaC for existing projects, always default to google_project_iam_member to avoid unintended access revocation caused by authoritative iam_binding or globally authoritative iam_policy resources.

TIP

Local authentication blind spot: Decoupled gcloud and ADC: When writing and testing Terraform locally, AWS CLI and SDKs share ~/.aws/credentials. GCP separates them. Running gcloud auth login only authenticates the CLI itself. To run Terraform or execute code via GCP SDKs, you must separately run gcloud auth application-default login to generate local Application Default Credentials (ADC). Missing this step causes a common point of confusion where CLI commands work flawlessly while applications throw authentication errors.


2. Networking: Global VPCs, Shared VPCs, and Software-Defined Perimeters

Global VPCs and Regional Subnets

An AWS VPC is confined to a single Region, and each Subnet resides within a specific Availability Zone (AZ). Routing between two cross-region VPCs requires VPC Peering or a Transit Gateway.

In GCP, a VPC is a global resource, whereas subnets are regional resources:

 AWS Architecture (Regional VPC):
 [Region: us-east-1]         [Region: ap-northeast-1]
 +-----------------------+   +-----------------------+
 | VPC: 10.0.0.0/16      |   | VPC: 10.1.0.0/16      |
 |  +-- Subnet AZ-a      |<->|  +-- Subnet AZ-a      |
 |  +-- Subnet AZ-b      |   |  +-- Subnet AZ-b      |
 +-----------------------+   +-----------------------+
 (Cross-region requires Peering or Transit Gateway)

 GCP Architecture (Global VPC):
 +---------------------------------------------------+
 | Global VPC Network                                |
 |  +-- Region: us-central1 (Subnet: 10.128.0.0/20)  |
 |  +-- Region: asia-east1  (Subnet: 10.140.0.0/20)  |
 |                                                   |
 |        <--- Direct Internal Routing --->          |
 +---------------------------------------------------+

This architecture introduces three fundamental shifts:

  1. Native cross-region internal communication: A VM in asia-east1 and a VM in us-central1 communicate directly via internal IP addresses as long as they reside in the same VPC. Traffic traverses Google’s global private fiber backbone without requiring VPC peering.
  2. Subnets span all zones: Subnets are not tied to a specific zone. You only need to allocate a single subnet per region; all zones in that region automatically share this address space.
  3. No public vs. private subnet distinction: GCP has no Internet Gateway (IGW) resource. Whether a VM can reach the public internet depends entirely on whether it is assigned an external public IP, or whether Cloud NAT is configured for that region.

NOTE

Cross-project networking: Shared VPC: Comparable to sharing subnets via AWS Resource Access Manager (RAM), GCP’s Shared VPC allows a centralized Host Project to share its VPC network with multiple Service Projects. Central network teams manage subnets and firewalls in the Host Project, while individual application teams deploy VMs and GKE clusters in their respective Service Projects, aligning with project-level IAM isolation boundaries.

Firewall Mechanisms and Demystifying the Three Types of “Tags”

AWS uses a two-tier model: stateful Security Groups attached to ENIs (allow-only) paired with stateless NACLs attached to subnets (supporting allow/deny with rule evaluation order).

GCP collapses both into a single system: VPC Firewall Rules:

resource "google_compute_firewall" "allow_lb_to_web" {
  name                    = "allow-lb-to-web"
  network                 = google_compute_network.main.id
  direction               = "INGRESS"
  priority                = 1000
  source_ranges           = ["35.191.0.0/16", "130.211.0.0/22"] # Google LB probe and GFE-to-backend source ranges
  target_service_accounts = [google_service_account.web.email]

  allow {
    protocol = "tcp"
    ports    = ["8080"]
  }
}

While AWS relies on a single tagging mechanism, GCP splits the concept into three distinct, non-interchangeable mechanisms:

Tag TypeDefinition Level & CharacteristicsCore Purpose & Limitations
LabelsResource level (Key-Value pairs)Used exclusively for cost allocation / billing breakdown and Console filtering; cannot be used in IAM or firewall conditions
Tags (RM Tags)Organization / Project level (hierarchical inheritance)Strongly typed and governed by IAM; can be referenced in IAM conditions and Org Policies
Network TagsVM attribute (list of plain text strings)Used exclusively for target filtering in VPC firewall rules and routes; lacks IAM access controls

In security-sensitive environments, always configure firewall rules using Target Service Accounts instead of Network Tags to prevent instances from bypassing network perimeters through arbitrary tag modifications.

Private Connectivity and Load Balancing Architectures

AWS unifies private, non-internet-routable communication under VPC Endpoints. GCP separates private access into three distinct mechanisms based on the target architecture:

  1. Private Google Access: Enabled with a single toggle at the subnet level, allowing VMs with only internal IP addresses to reach Google APIs (such as GCS and BigQuery) completely free of charge, without provisioning dedicated endpoint network interfaces.
  2. Private Service Connect (PSC): The direct equivalent of AWS PrivateLink, providing custom internal IP endpoints to connect securely to third-party SaaS providers or private services published across VPCs.
  3. Private Services Access (PSA): Implemented as VPC Peering to connect directly to dedicated internal subnets hosting Google-managed services (such as Cloud SQL and Memorystore). Cloud SQL now recommends PSC for private IP connectivity (the console default for new projects), making PSA the earlier-generation mechanism.

For egress and load balancing:


3. Kubernetes: GKE vs. EKS Cloud Integrations

For Certified Kubernetes Administrators (CKAs), core Kubernetes constructs such as kubectl, Deployment, and Service translate seamlessly. The key differences lie in how each platform integrates with the underlying cloud control plane.

Standard vs. Autopilot Modes

EKS manages compute fleets using Managed Node Groups, Karpenter, or Fargate. GKE offers two cluster operation modes at creation time:

Evaluation DimensionGKE StandardGKE Autopilot
Node ManagementUser-managed Node PoolsWorker nodes fully managed by Google
Control PlaneSupports Zonal (single zone) and Regional (HA)Strictly Regional (replicated across multiple zones)
Billing BasisNode VM specifications and instance countsPod-declared Resource Requests
Node AccessFull SSH access and node-level debuggingSSH disabled; troubleshooting relies entirely on Cloud Logging
Upgrade MechanismManual, custom, or managed via Release ChannelsStrictly locked to Release Channels for automatic upgrades

WARNING

Single point of failure blind spot in Standard clusters: In AWS EKS, the control plane is always managed by AWS across multiple availability zones. GKE Standard, however, permits the creation of Zonal clusters (where the control plane resides in a single zone, reducing cluster management fees but introducing a single point of failure). For production environments, always provision Regional clusters to guarantee control plane high availability.

Under GKE Autopilot, operational thinking changes significantly: resource requests directly dictate infrastructure spend; Google assumes all node maintenance duties; and observability shifts entirely to Cloud Logging and kubectl describe.

VPC-Native Clusters and Secondary IP Ranges

In AWS EKS, the AWS VPC CNI assigns Pod IPs directly from the primary subnet address space, often leading to subnet CIDR exhaustion as clusters scale.

GKE defaults to a VPC-Native architecture leveraging Alias IPs:

 GCP Subnet CIDR Layout for GKE:
 +---------------------------------------------------+
 | Primary CIDR: 10.0.0.0/24      (Node VMs)         |
 | Secondary CIDR 1: 10.4.0.0/14  (Pods)             |
 | Secondary CIDR 2: 10.8.0.0/20  (Services)         |
 +---------------------------------------------------+

Because secondary ranges are natively routable across the entire VPC, Google Cloud Load Balancers can bypass NodePorts and kube-proxy entirely using Network Endpoint Groups (NEGs). Traffic routes directly to Pod IPs (Container-Native Load Balancing), significantly reducing network hops and latency.

Workload Identity Federation for GKE

In AWS EKS, pods accessing AWS APIs historically relied on IRSA (requiring an IAM OIDC Provider and Trust Policies), with EKS Pod Identity as the more recent option.

GCP’s equivalent solution is Workload Identity Federation for GKE. When enabled, the GKE Metadata Server intercepts credential requests on nodes and exchanges the Kubernetes ServiceAccount (KSA) token for a short-lived GCP access token.

GCP’s current best practice is to grant IAM roles directly to the KSA principal using the following URI format:

principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/PROJECT_ID.svc.id.goog/subject/ns/NAMESPACE/sa/KSA_NAME

This principal can be bound directly as a member in any GCP resource IAM policy, removing the need to provision an intermediate GCP Service Account.

IMPORTANT

Project Number vs. Project ID: When configuring Workload Identity principals, the string path requires the numeric Project Number, not the alphanumeric Project ID. This mismatch is a common debugging pitfall in cross-cloud migrations.

Automatic Rolling Upgrades via Release Channels

In EKS, Kubernetes version upgrades require operators to manually trigger control plane and node group updates.

GKE introduces Release Channels (Rapid, Regular, Stable, plus Extended for long-term support on Standard clusters) by default:


4. Serverless Boundaries: Unified Workloads on Cloud Run

While AWS splinters serverless compute across Lambda (pure functions), App Runner (simplified containers), and ECS on Fargate (full containerized tasks), GCP unifies these workloads under Cloud Run.

The core value proposition of Cloud Run is that a single standard Docker container image and a unified IAM model can handle multiple execution patterns:

Execution ModeTrigger & LifecycleIdeal Use Cases
ServicesHTTP / gRPC request-driven (scales to zero)Web APIs, microservices, webhooks
JobsInvoked on demand or scheduled via Cloud SchedulerData transformation, DB migrations, batch reporting
Worker PoolsContinuously pull messages from queues like Pub/SubAsynchronous event processing, background queue workers

Standalone Cloud Functions have now been fully folded into the Cloud Run functions family. For operations teams running stateless workloads, Cloud Run delivers serverless execution without the operational overhead of managing Kubernetes clusters or nodes.


5. Operational Boundaries: Audit Logging, API Ecosystem, and Billing

Audit Logging Mechanisms (vs. CloudTrail)

GCP’s Cloud Audit Logs enforces clear architectural boundaries around costs and enablement:

The API Ecosystem and Committed Use Discounts (CUDs)

  1. APIs require explicit enablement; disabling them is destructive: AWS accounts enable all services by default. In GCP, each Project must explicitly enable APIs before use (e.g., container.googleapis.com), typically managed declaratively in Terraform via google_project_service. Critically, disabling an API (such as disabling the Cloud Run API) is a destructive operation that permanently deletes all existing instances and resources managed under that service within the project.
  2. Flexible cross-service discounts (CUDs): While AWS Savings Plans come in Compute, EC2 Instance, and SageMaker variants, GCP’s Committed Use Discounts (CUDs) provide both resource-based commitments for Compute Engine and Spend-based Flexible CUDs. The latter applies commitments simultaneously across Compute Engine, GKE, and Cloud Run, offering greater purchasing flexibility for mixed architectures.