Multi-Cloud Networking & CIDR Strategy Guide
This document outlines the standardized approach for managing IP address space across AWS, Azure, and GCP to ensure zero overlaps in a hybrid-cloud environment.
1. Global CIDR Allocation (The Root Registry)
We use a central registry (live/network_registry.hcl) as the single source of truth. The 10.0.0.0/8 private IP space is divided into large blocks for each provider.
Core Allocation Map
| Cloud Provider | Purpose | CIDR Range |
|---|---|---|
| AWS | Development | 10.10.0.0/16 |
| AWS | Staging | 10.11.0.0/16 |
| AWS | Production | 10.12.0.0/16 |
| Azure | Development | 10.20.0.0/16 |
| GCP | Development | 10.30.0.0/16 |
Environment-Level Mapping (Example)
Each environment is allocated a full /16 range to provide maximum scalability.
2. Avoidance Zones (Cloud Defaults)
To prevent routing conflicts with "Default VPCs" or "Auto-Mode" networks, we explicitly AVOID the following ranges:
- AWS Default VPCs:
172.31.0.0/16 - Azure Portal Defaults:
10.0.0.0/16 - GCP Auto-Mode VPCs:
10.128.0.0/9(Matches anything from10.128.x.xto10.255.x.x)
3. Hierarchical Subnetting (Internal VPC Design)
Within a single /16 environment (65,536 IPs), we use a hierarchical structure to accommodate different resource types.
Subnet Capacity per /16
| Subnet Size | Total IPs | Max Subnets per /16 |
Ideal Use Case |
|---|---|---|---|
/18 |
16,384 | 4 | Large Clusters (Secondary Ranges) |
/24 |
256 | 256 | Standard Nodes, Management, LBs |
4. Automation with cidrsubnet
We avoid hardcoding subnet ranges. Instead, we use the Terraform cidrsubnet function for mathematical precision and portability.
Usage Pattern
cidrsubnet(base_cidr, newbits, index)
- To get a
/18(from a/16):newbits = 2 - To get a
/24(from a/16):newbits = 8
Implementation Example
locals {
vpc_cidr = "10.30.0.0/16"
}
# The First /24 for Nodes
node_range = cidrsubnet(local.vpc_cidr, 8, 0) # "10.30.0.0/24"
# A /24 for Pods
pod_range = cidrsubnet(local.vpc_cidr, 8, 1) # "10.30.1.0/24"
5. Expansion Workflow: Adding New Ranges and Subnets
To maintain a conflict-free network as the platform scales, you MUST follow this "Registry-First" workflow. This process mathematically guarantees that new environments or subnets will not overlap with existing infrastructure.
Step 1: Claim the Block in the Global Registry
Before touching any Terraform code, you must register the new environment in live/network_registry.hcl.
Example: Adding a new gcp-prod environment.
1. Check the registry for the next available /16 block.
2. Add the entry:
gcp = {
dev = "10.30.0.0/16"
stg = "10.31.0.0/16"
prod = "10.32.0.0/16" # <-- NEW ENTRY
shared = "10.33.0.0/16"
}
Step 2: Ingest the CIDR via Terragrunt
Create the terragrunt.hcl for the new environment and configure it to pull the CIDR dynamically. Do not hardcode the IP.
# live/gcp/prod/vpc/terragrunt.hcl
locals {
network_registry = read_terragrunt_config(find_in_parent_folders("network_registry.hcl"))
cloud = "gcp"
env = "prod"
}
inputs = {
# Dynamically pulls "10.32.0.0/16"
vpc_cidr = local.network_registry.locals.cidr_map[local.cloud][local.env]
}
Step 3: Carve Subnets using cidrsubnet
Inside your Terraform module, use cidrsubnet to slice the vpc_cidr into smaller, usable blocks (e.g., /24 for Nodes).
# modules/gcp/vpc/main.tf
variable "vpc_cidr" {} # Inherits "10.32.0.0/16"
# GKE Pod Range (/24)
resource "google_compute_subnetwork" "prod_pods" {
name = "prod-pods-subnet"
ip_cidr_range = cidrsubnet(var.vpc_cidr, 8, 0) # "10.32.0.0/24"
}
# GKE Node Range (/24)
resource "google_compute_subnetwork" "prod_nodes" {
name = "prod-nodes-subnet"
ip_cidr_range = cidrsubnet(var.vpc_cidr, 8, 1) # "10.32.1.0/24"
}
How this prevents overlap:
The cidrsubnet function guarantees uniqueness within the VPC. Because the parent vpc_cidr (e.g., 10.30.0.0/16) is globally unique (secured by Step 1), any subnet carved out of it using cidrsubnet is mathematically guaranteed to be unique across your entire Multi-Cloud platform.
6. Automated Validation
To ensure that no overlapping CIDR ranges are ever introduced, we automate the validation process. Every plan or apply command will automatically trigger our validation script before Terraform proceeds.
Implementation
Add the following configuration to your root.hcl:
# root.hcl
terraform {
before_hook "validate_cidrs" {
commands = ["plan", "apply"]
execute = ["bash", "${get_repo_root()}/scripts/validate-cidrs.sh"]
}
}
How it works:
- Automatic Execution: Whenever you run
terragrunt planorterragrunt apply, Terragrunt executes thescripts/validate-cidrs.shscript first. - Failure on Overlap: If the script detects an overlapping range, it exits with a non-zero status, and Terragrunt will immediately stop execution.
- CI/CD Safety: This acts as a final safety gate in your CI/CD pipeline, preventing any PR that introduces an overlapping CIDR from ever being applied to infrastructure.
7. Summary of Steps Taken
- Registry Creation: Initialized
live/network_registry.hcl. - Conflict Research: Identified and avoided cloud-provider default ranges.
- Registry Integration: Linked environment
terragrunt.hclfiles to the registry. - Capacity Planning: Verified
/16environment blocks and/24subnets. - Documentation: Created this guide and updated the root
README.md. - Automated Validation: Implemented a pre-execution hook in
root.hcl.