Most migration failures are planning failures: an unknown dependency, an address range that overlaps, a database that turns out to be ten times larger than anyone thought. This post is the planning half of a Google Cloud to AWS migration. The next post covers execution.
The shape of the work
flowchart LR
A[Discover<br/>inventory and dependencies] --> B[Assess<br/>strategy per workload]
B --> C[Design<br/>landing zone and network]
C --> D[Plan waves<br/>pilot first]
D --> E[Migrate and validate]
E --> F[Optimise and decommission GCP]
1. Discover: build a real inventory
Start from data, not memory. Cloud Asset Inventory lists every resource across projects:
gcloud asset search-all-resources --scope=organizations/123456789012 \
--format="csv(assetType,name,location,project)" > gcp-inventory.csv
# quick counts by type
cut -d, -f1 gcp-inventory.csv | sort | uniq -c | sort -rn | head -20
For each workload capture:
| Field | Why |
|---|---|
| Owner and business criticality | Who signs off, and how much downtime is acceptable |
| Compute: VMs, GKE workloads, Cloud Run services | Target platform choice |
| Data stores and sizes | Transfer time and method |
| Inbound and outbound dependencies | Wave grouping; avoids cross-cloud chatter |
| Google-specific APIs used | Refactoring effort (Firestore, BigQuery, Pub/Sub semantics) |
| Current monthly cost and performance | The baseline you must beat or match |
Dependencies are the part people get wrong. VPC Flow Logs, service mesh telemetry or simply reading connection strings in configuration files will show who talks to whom.
2. Assess: map services and pick a strategy
| Google Cloud | AWS target | Notes |
|---|---|---|
| Compute Engine | EC2 | Map machine types by vCPU, memory and generation; consider Graviton |
| Managed instance groups | EC2 Auto Scaling groups | |
| GKE | EKS | Workload identity, ingress and storage classes change |
| Cloud Run | ECS on Fargate | Closest serverless-container match |
| Cloud Run functions | Lambda | Runtime and trigger changes |
| Cloud Storage | S3 | Object paths stay; signed URL code changes |
| Cloud SQL for PostgreSQL or MySQL | RDS or Aurora | DMS replication for low downtime |
| Memorystore | ElastiCache (Redis or Valkey) | |
| Pub/Sub | SNS with SQS, or Amazon MSK | Ordering and delivery semantics differ |
| Artifact Registry | ECR | |
| Secret Manager | Secrets Manager | |
| Cloud Monitoring and Logging | CloudWatch, or keep Prometheus and Grafana | |
| Cloud DNS | Route 53 | |
| Cloud Load Balancing | ALB, NLB, CloudFront | Google’s global anycast LB has no single AWS twin |
| IAM, service accounts | IAM roles, IAM Identity Center |
Then choose a strategy per workload:
| Strategy | Use when |
|---|---|
| Rehost (lift and shift) | VMs that just need to run; quickest, least risk |
| Replatform | Move to a managed equivalent, e.g. self-managed MySQL VM to RDS |
| Refactor | Deep dependency on a Google-only service, or a planned redesign |
| Retire | Nobody uses it; the inventory usually finds a few |
Rule of thumb: change one thing at a time. Moving cloud and redesigning at once doubles the number of things that can go wrong.
3. Design the landing zone
Build the destination before moving anything into it.
flowchart TB
M[Management account<br/>billing and Organizations only] --> SEC[Security account<br/>CloudTrail, GuardDuty, Config]
M --> LOG[Log archive account]
M --> NET[Network account<br/>Transit Gateway, VPN]
M --> PRD[Production workload account]
M --> NPD[Non-production workload account]
NET --- PRD
NET --- NPD
- AWS Organizations with separate accounts for production and non-production, so a mistake in one cannot touch the other.
- IAM Identity Center connected to your identity provider (often the same Google Workspace or Entra ID directory), with permission sets per role.
- Guardrails: service control policies that deny leaving approved regions, disabling CloudTrail or creating IAM users with access keys.
- Logging: organisation CloudTrail to the log archive account, GuardDuty and AWS Config enabled everywhere.
- Tagging:
Project,Env,Owner,CostCenter, enforced with tag policies from day one.
4. Design the network
This is where Google and AWS differ most.
| Google Cloud | AWS |
|---|---|
| A VPC is global; subnets are regional | A VPC is regional; subnets are per availability zone |
| Firewall rules on the network, matched by tags | Security groups on interfaces, network ACLs on subnets |
| One VPC can span regions | Connect regions with Transit Gateway peering |
Plan the address space so nothing overlaps, because the two clouds must route to each other during the migration:
| Network | CIDR |
|---|---|
| GCP existing VPC | 10.10.0.0/16 |
| AWS production VPC, ap-south-1 | 10.40.0.0/16 |
| AWS non-production VPC, ap-south-1 | 10.41.0.0/16 |
| AWS shared services VPC | 10.42.0.0/20 |
Each AWS VPC gets public, private-application and private-data subnets across three availability zones.
During the migration both clouds are connected with HA VPN on the Google side and a Transit Gateway VPN attachment on the AWS side, with BGP. Measure the throughput early, because it decides how long data transfer will take.
5. Identity and access mapping
| Google concept | AWS equivalent |
|---|---|
| Google group with a role on a project | Identity Center group with a permission set on an account |
| Service account for a VM | IAM role in an instance profile |
| GKE workload identity | EKS Pod Identity or IRSA |
| Service account JSON key in CI | GitHub or GitLab OIDC federation to an IAM role |
Do not carry long-lived keys across. The migration is the right moment to remove them.
6. Plan the waves
flowchart LR
W0[Wave 0<br/>landing zone, network, CI] --> W1[Wave 1 pilot<br/>low-risk internal service]
W1 --> W2[Wave 2<br/>stateless services]
W2 --> W3[Wave 3<br/>data stores and dependants]
W3 --> W4[Wave 4<br/>edge, DNS, decommission]
- Group by dependency, so services that talk constantly move together and do not pay cross-cloud latency and egress for long.
- Pilot first with something real but low-risk. It tests the runbook, the tooling and the team.
- Data moves drive the schedule. A 2 TB database over a 500 Mbps VPN takes about 9 hours for the copy alone, before change replication.
7. Define success and rollback before starting
For each workload write down:
- Success criteria: error rate, p95 latency and throughput no worse than the GCP baseline; all scheduled jobs ran; costs within the estimate.
- Rollback trigger: for example error rate above 2% for 15 minutes after cutover.
- Rollback method: DNS back to GCP, with data written in AWS replayed or reconciled.
- Decommission date: GCP resources stay read-only for an agreed period, then are deleted, otherwise you pay for two clouds.
8. Estimate the costs honestly
- Egress from Google Cloud for the data transfer is often the largest one-off cost.
- Dual running: both environments are billed during the migration window.
- Steady state on AWS: use the AWS Pricing Calculator with right-sized instances, not a one-to-one copy of oversized GCP machines.
Planning checklist
- Inventory exported and dependencies mapped
- Strategy chosen per workload
- Landing zone, guardrails and logging in place
- Non-overlapping CIDRs and VPN tested for throughput
- Identity mapped, long-lived keys removed
- Waves planned with a pilot
- Success criteria, rollback and decommission dates written
The next post moves the workloads: connectivity, databases, files, servers, containers and cutover.