Skip to main content

Scalable

A Scalable system grows predictably without architectural failure. The AWS Baseline is sized for growth before the first apply, because re-addressing a live network means rebuilding it: the address plan reserves space for 16 regions and 8 workload stages per region, a new region is a folder-level change, a new account is data rather than code, and the workloads scale horizontally on managed services.

Growth dimensions

DimensionHow the platform growsWhat changes
AddressesThe organization supernet is 10.0.0.0/8 (or /11 with the compact map). Each region gets a /12, each workload stage a /16 with /18 private subnets sized for EKS pod density, and one /14 per region stays free for a future OUNothing: the space is reserved from the start
RegionsRegions are discovered from the region.hcl files in the tree. The map already describes us-east-1 as the planned second regionAdd the region's folders and stack files; IPAM discovers it and the region SCP allows it
Accounts and stagesAccounts are created as code from a map; a workload account instantiates the plat-account template with nothing account-specificAdd the account to the map and an account.hcl; give any VPC a map entry; place a stage in an isolation domain
Inter-region trafficTransit Gateway peering between each region and the home region, with static routes per isolation domain, is built and off by default (enable_tgw_peering, about $36 per month per peering)Flip the switch in that region's network.hcl
ComputeA baseline EKS node group sized per stage (dev 2 to 3 nodes, staging and prod 3 to 4) that Cluster Autoscaler moves between those bounds, Karpenter capacity for the application under a per-stage vCPU ceiling (32, 64, 128), and a horizontal pod autoscaler on the application (prod 3 to 10 replicas at 60% CPU)Per-stage values, tagged @optional:
Data processingGlue worker type and count per job (G.1X, 2 workers by default); Lambda for event handling with configurable memory and timeoutPer-stage values in the ETL stage file
CI capacityOptional self-hosted runners on Spot instances, capacity-optimized with on-demand failover, that scale to zerogithub-runner unit in the auto account

Why one address plan matters

Every CIDR in the organization is defined once, in the VPC map at the root of the landing-zone repository, and delivered by IPAM as typed outputs. VPC units look their allocation up by ipam_key (plat-prod, core-network), Availability Zones are derived from the region, and a script rejects any private IP range typed anywhere else. Two maps ship: the active one for container platforms with high pod density, and a compact one for workloads without Kubernetes. The choice is made once, before the first deployment, because every address differs between them. The IPAM explainer shows the pool hierarchy.

Adding a region

A second region is additive. The region folders are created under each account that needs them, each with a region.hcl naming the slug and a stack file listing the region's units. The IPAM unit reads the tree, builds pools only for live regions, and fails the plan if a folder disagrees with the map. The region-restriction SCP allows every region that has folders. Regional units (VPCs, the Transit Gateway, security detectors, keys, logging) live under the region folder; organization-wide singletons (Organizations, IAM, public DNS zones, IPAM, the Client VPN endpoint, the state backend) live once under global, so nothing is duplicated by mistake. The single Client VPN endpoint already authorizes and routes every region; peering supplies the path.

Adding a stage

A fifth workload stage such as qa is an entry in the organizations account map, an account.hcl, a VPC map entry, a region folder whose stack file instantiates plat-account, and a place in an isolation domain. The seven landing-zone units the stage needs (account baseline, observability link, VPC, VPC endpoints, Transit Gateway attachment, private zone association, SSM publish) come from the template; the tag policy lists the plat stage slugs (prd, stg, dev, sbx) in modules/organizations/tags.tf, so the new slug is added there. Blueprints then add the stage to their common.hcl, CI matrices and GitHub Environments. The landing zones page explains why stages are accounts.

Workload scaling

The Web App Blueprint runs on managed services sized per stage: DocumentDB replicas and Redis nodes, a CloudFront distribution in front of the static front end, and a cluster that scales in three layers. The horizontal pod autoscaler adds pods when CPU passes its target. Karpenter adds nodes for those pods, choosing an instance type per pending pod, preferring Spot, and stopping at a per-stage vCPU ceiling that bounds the bill. Cluster Autoscaler keeps the system baseline the right size underneath, between the node group's own minimum and maximum. The two autoscalers own disjoint sets of nodes, so neither can take capacity from the other.

The Data and ETL Blueprint processes on demand: an S3 upload invokes a Lambda that starts a Glue job, so nothing runs when nothing arrives. The EKS and Glue explainers describe the knobs; the Reliable page describes the same values from the failure side.

How you verify it

  • IPAM console in the network account: the organization pool, one regional pool per live region, and the core and plat pools beneath it.
  • The VPC map in your landing-zone repository: the reserved regions and the free /14 per region.
  • EKS console in a workload account: the managed node group's minimum, maximum and desired sizes.
  • kubectl get nodes -L karpenter.sh/nodepool against a cluster: the baseline nodes and the Karpenter ones, labeled.
  • kubectl get hpa -n <app namespace> against the prod cluster: the 3 to 10 replica range.
  • network.hcl in each region folder of the network account: the enable_tgw_peering switch and its price.

The Transit Gateway explainer covers the route tables that a new region or stage joins.