Create your own
Lesson illustration

Designing a Secure Multi-AZ VPC Architecture

Good to continue from requirements into the network boundary that makes those requirements enforceable. In the previous lesson, you separated the exchange’s critical order and cancellation path from lower-criticality reporting and defined targets for availability, recovery, security, and latency. This lesson turns that brief into a VPC design that can survive an Availability Zone failure, limits public exposure, and makes outbound connectivity deliberate rather than accidental.

The target is not “a VPC with public and private subnets.” It is a network design you can defend in an interview: clear trust boundaries, routes that match each workload’s purpose, private access to AWS services, layered controls, and known failure behavior.


Begin with failure domains and trust zones

A VPC is regional; a subnet belongs to exactly one Availability Zone (AZ). High availability therefore comes from placing equivalent capacity in multiple AZs and ensuring that routing does not silently create a dependency on one AZ.

For the exchange scenario, assume one primary AWS Region with three AZs. Three AZs provide better capacity and maintenance resilience, though a two-AZ design remains acceptable where the service, cost profile, or Region makes it appropriate. The essential requirement is that the critical service can continue when one AZ is unavailable.

A practical layout has four subnet roles in each AZ:

Subnet roleTypical contentsInternet reachabilityDesign purpose
Public ingress/egress subnetInternet-facing load balancer nodes, NAT Gateway, optionally egress firewall componentsDirect route to Internet GatewayThe only subnet tier that needs a route to the public internet
Private application subnetECS tasks, EKS nodes and Pods, internal services, worker processesOutbound-only through controlled egress; no direct Internet Gateway routeRuns the application and order-processing services without public IPs
Isolated data subnetRDS, cache nodes, internal stateful servicesNo default internet routeLimits network paths to high-value data systems
Private endpoint subnet (optional but useful at scale)Interface VPC endpoint network interfacesNo public routeMakes endpoint capacity, IP use, and security policy easier to manage

For a senior answer, say explicitly that a public subnet does not mean every resource in it is publicly reachable. A subnet is called public because its route table has a route to an Internet Gateway. A workload is reachable only when several conditions align: it has a public address where applicable, its security group permits traffic, its network ACL permits traffic, and a route exists.

Likewise, a private application subnet can use a NAT Gateway for outbound connections without being publicly reachable. NAT permits connections initiated from the private side; it is not a path for unsolicited inbound connections.

The AWS reference architecture below shows the core two-AZ version of this pattern: an internet-facing Application Load Balancer and NAT Gateways in public subnets, with application servers in private subnets. We will strengthen that baseline by adding an isolated data tier, endpoint strategy, and explicit egress policy.

AWS’s VPC reference design places an Application Load Balancer and one NAT Gateway in each public subnet across two Availability Zones, while Auto Scaling application servers remain in private subnets. An S3 Gateway Endpoint gives private workloads a path to S3 without using the NAT Gateway.

Before continuing, read the AWS VPC reference. It is a concise, authoritative baseline for the public/private routing and security-group relationship.

Example: VPC with servers in private subnets and NAT

Read AWS’s VPC User Guide example to anchor the baseline multi-AZ pattern: private workloads receive traffic through a load balancer, use NAT only for outbound internet access, and can reach S3 through a Gateway Endpoint.

In Overview, read the architecture summary. Identify the distinct roles of public subnets, private subnets, the load balancer, NAT Gateways, and the S3 endpoint. Then, in Routing, read the routing explanation. Compare the public default route to the private default route and note that the S3 route is more specific than general internet egress. Finally, in Security, read the load balancer rule guidance. Focus on why an application server should accept traffic from the load balancer security group rather than from an unrestricted CIDR range.

Establish address space that will not become a constraint

CIDR allocation is easy to overlook until an EKS rollout, a VPC peering connection, an acquisition, or a second Region reveals that the initial address space is too small or overlaps another network.

For a production platform, reserve a non-overlapping VPC range after confirming enterprise IP address management constraints. A sample primary Region allocation could be :

TierAZ A exampleAZ B exampleAZ C exampleWhy this size
Public ingress/egressSpace for ALB scaling, NAT, firewall endpoints, and future ingress components
Private applicationHeadroom for ECS tasks or Kubernetes Pod IP consumption
Isolated dataDatabase, cache, and internal stateful capacity
Endpoint/shared servicesInterface endpoint ENIs and private shared services

These are examples, not universal subnet sizes. The justification matters more than the numbers:

  • EKS using the AWS VPC CNI consumes VPC addresses for Pods, which can exhaust casually sized application subnets well before CPU or memory is exhausted.
  • AWS reserves IP addresses in every subnet, so nominal CIDR capacity is not fully available.
  • Future VPC peering, Transit Gateway, on-premises connectivity, and disaster-recovery networks require non-overlapping ranges.
  • A secondary Region should have a separate, pre-reserved CIDR range. Do not discover overlap during a regional-recovery event.

For a lead-level design, document the AZ IDs rather than assuming an AZ name such as us-east-1a maps to the same physical AZ in every AWS account. This matters when coordinating network topology across accounts.


Route tables express intent and failure behavior

The route table associated with a subnet is the clearest expression of its allowed network paths. Keep route tables specific to a purpose and, where required, specific to an AZ. A single shared “private route table” is often the beginning of hidden cross-AZ dependencies.

Public subnet routing

Each public subnet needs the VPC-local route and a default route to the Internet Gateway:

DestinationTargetMeaning
VPC CIDRlocalCommunication inside the VPC
Internet GatewayIPv4 internet path for public-tier resources
, if dual stackInternet GatewayIPv6 internet path for public-tier resources

The NAT Gateway lives in this subnet and has an Elastic IP. Internet-facing load balancer nodes also use public subnets, but the application tasks behind them do not need public addresses.

Private application subnet routing

Each private application subnet should have a route table dedicated to its AZ:

DestinationTargetMeaning
VPC CIDRlocalInternal VPC communication
NAT Gateway in the same AZControlled IPv4 egress for approved external dependencies
S3 managed prefix listS3 Gateway EndpointPrivate, direct route to S3
DynamoDB managed prefix listDynamoDB Gateway EndpointPrivate, direct route to DynamoDB, if needed
, if dual stackEgress-only Internet GatewayOutbound-only IPv6 internet connectivity

The important design point is same-AZ NAT routing. If workloads in AZ A use a NAT Gateway in AZ B, then an AZ B failure can remove egress for otherwise healthy AZ A workloads. It also creates cross-AZ data transfer charges and unnecessary latency.

An AZ-local NAT design does not mean every service must depend on NAT. Critical workloads should use VPC endpoints for AWS dependencies such as secrets retrieval, logging, image pulls, and artifact access. This reduces both NAT cost and the blast radius of an egress failure.

Isolated data subnet routing

The data tier should normally have only:

DestinationTargetMeaning
VPC CIDRlocalConnectivity to approved services within the VPC
Specific endpoint prefix list, only if requiredGateway EndpointNarrow access to a necessary AWS service

There is deliberately no default route to a NAT Gateway or Internet Gateway. An RDS instance should not download packages, call arbitrary external APIs, or need general internet access. Operational access should be performed through managed controls and application-level processes, not by turning the data subnet into an application subnet.

Multi-AZ NAT: resilience before apparent savings

A common interview trap is to create one NAT Gateway because it is expensive, then route every private subnet through it. That architecture may work, but it makes a single AZ and its NAT path a dependency for all workloads’ external access.

AWS recommends at least one NAT Gateway in each AZ where workloads run. The following AWS Networking blog explains both the distributed per-AZ approach and the alternative centralized egress model.

Using NAT Gateways with multiple-Amazon VPCs at scale | Networking & Content Delivery

Read AWS’s Networking & Content Delivery guidance to distinguish a resilient per-AZ NAT design from centralized egress, and to understand why endpoints should remove S3 and DynamoDB traffic from NAT paths.

Read the resiliency and endpoint recommendation. Focus on the paired benefit: reduced AZ dependency and reduced cross-AZ transfer, not simply “more NAT Gateways.” Then read the Distributed and centralized architectures for NAT Gateway discussion, beginning with the two architecture choices. Treat centralized egress as an organizational and security-control decision, not an automatic cost optimization.

There are two defensible egress patterns:

  1. Distributed egress within the workload VPC. Each AZ routes to its local NAT Gateway. This is usually the straightforward choice for a single product VPC or a high-availability exchange service with independent teams.

  2. Centralized egress through a dedicated egress VPC. Multiple workload VPCs reach an egress VPC through Transit Gateway, where firewall inspection, proxying, logging, and NAT are centrally managed. This can fit a regulated multi-account environment, but it introduces additional routing, inspection, failure, and capacity dependencies. It must still preserve AZ locality.

For the exchange platform, begin with distributed NAT in the production workload VPC unless a validated enterprise networking pattern already mandates centralized inspection. Do not introduce Transit Gateway merely because it sounds more sophisticated.


Use VPC endpoints to reduce egress dependency

A NAT Gateway is appropriate for approved third-party APIs, software repositories, certificate services, or vendor endpoints. It is usually the wrong default for calls to AWS services available through VPC endpoints.

There are two endpoint types with different network behavior.

Endpoint typeCommon servicesNetwork mechanismKey controls
Gateway EndpointS3, DynamoDBRoute-table entry using an AWS-managed prefix listEndpoint policy, bucket/table policy, workload IAM policy
Interface EndpointSecrets Manager, STS, ECR APIs, CloudWatch Logs, KMS, SSM, many othersPrivate Elastic Network Interfaces in selected subnetsEndpoint security group, endpoint policy, workload IAM policy, private DNS

For an exchange workload, a realistic initial endpoint set might include:

  • S3 Gateway Endpoint for artifacts, immutable audit exports, backups, and controlled data retrieval.
  • DynamoDB Gateway Endpoint if the platform legitimately uses DynamoDB.
  • Secrets Manager Interface Endpoint so workloads retrieve credentials without requiring NAT.
  • CloudWatch Logs Interface Endpoint for private log export.
  • ECR API and ECR Docker Interface Endpoints, together with the S3 Gateway Endpoint used for image layers.
  • STS Interface Endpoint where workloads use AWS STS without internet egress.
  • KMS Interface Endpoint if the private workload needs KMS API access.
  • SSM, EC2 Messages, and SSM Messages Interface Endpoints for managed operational access to EC2 nodes, where relevant.

Interface endpoints should be deployed in at least the AZs where the consuming workload runs. Enable private DNS so standard AWS service hostnames resolve to endpoint-private IP addresses inside the VPC. Otherwise, a workload may continue resolving the public service hostname and unexpectedly use NAT.

An endpoint is not a blanket authorization bypass. A successful request still requires:

  1. A route or local network path to the endpoint.
  2. Security-group permission for interface endpoints.
  3. An endpoint policy, where supported, that permits the intended call.
  4. IAM authorization for the workload role.
  5. A resource policy, where relevant, such as an S3 bucket policy or KMS key policy.

That layered model is valuable in regulated environments. For example, an S3 bucket policy can require access through a named VPC endpoint, while the task role is limited to a particular bucket prefix. A stolen credential used outside the approved endpoint path is then less useful.

Controlled egress means more than “put a NAT Gateway there”

A NAT Gateway translates addresses; it does not provide domain-aware allowlisting, TLS inspection, request inspection, or a full audit decision for each destination. If application security groups allow outbound TCP port to all destinations, the NAT Gateway provides a stable public source IP but not strict control of where applications can connect.

Choose the control level based on risk:

RequirementAppropriate approach
Stable source IP for an external vendor allowlistNAT Gateway Elastic IPs
Prevent direct internet access for AWS service callsVPC endpoints and endpoint policies
Restrict outbound access to specific external destinationsExplicit proxy, DNS-aware controls, or firewall controls with a maintained policy
Inspect and log egress flows centrallyEgress VPC with Network Firewall or an approved third-party firewall/proxy
Prevent unapproved package downloads from production workloadsNo general egress by default; use a controlled artifact repository and allowlisted paths

For the order-processing core, minimize external calls entirely. The matching and risk paths should not synchronously depend on a public SaaS endpoint. Third-party calls belong in asynchronous, retriable integration components with explicit timeout, retry, and circuit-breaker behavior.


Build microsegmentation with security groups

Security groups are stateful, apply to ENIs and resources, and should be the primary mechanism for application-level segmentation. A stateful rule means return traffic for an allowed connection is automatically permitted; you do not need a matching rule for every ephemeral response port.

The most maintainable pattern is to reference security groups as sources, not broad CIDR ranges. This makes the policy track workload identity rather than an address allocation that changes during deployments.

A minimal service-chain model could be:

Security groupInbound rulesOutbound rules
sg-alb-publicTCP from approved public CIDRs; in most public API cases, with AWS WAF policy at the load balancerTCP only to sg-api-service
sg-api-serviceTCP only from sg-alb-public; health-check path uses the same controlled sourceTCP only to sg-orders-db; TCP to required endpoint groups and approved egress path
sg-order-workerNo inbound rule unless a known internal caller requires oneOnly required ports to message infrastructure, database, endpoint groups, and observability services
sg-orders-dbTCP only from sg-api-service and sg-order-workerNormally no broad outbound rule; add only justified dependencies
sg-vpce-privateTCP from specific workload security groupsReturn traffic is statefully allowed

A few operational implications matter in interviews:

  • Do not permit database access from the entire VPC CIDR merely because it is “internal.”
  • Do not permit SSH from the internet. Prefer federated access, short-lived roles, Session Manager, and a recorded break-glass process. Identity design is covered in a later lesson.
  • A load balancer security group is the correct source for application-service inbound rules. The client IP address is not a reliable enforcement identity at the application target.
  • Restrict outbound rules where operationally feasible, but test dependencies carefully. Overly broad inbound rules are the greater immediate risk; overly restrictive egress rules can create hard-to-diagnose production failures if endpoint, DNS, certificate, and telemetry dependencies are not mapped.

Security groups give the required policy for the direct data path:

Intended connectionNetwork policy statement
Internet client to public APIClient reaches the public load balancer on TCP only
Public load balancer to API taskssg-alb-public reaches sg-api-service on the application listener port only
API tasks to order databasesg-api-service reaches sg-orders-db on TCP only
Worker to managed secret servicesg-order-worker reaches sg-vpce-private on TCP , with IAM authorization required as well
Database to internetNot permitted because no default route exists

This is an interview-quality distinction: routing determines whether a path can exist; security groups determine which identified workloads may use that path.


Use network ACLs as coarse subnet guardrails, not application firewalls

Network ACLs (NACLs) are stateless, subnet-level filters. Every permitted request path needs matching inbound and outbound rules because response traffic is not automatically allowed. Rules are evaluated in numbered order, with the first matching rule taking effect.

That makes NACLs useful for:

  • Coarse deny rules for a known malicious CIDR.
  • Organization-mandated subnet guardrails.
  • Additional control at a public subnet boundary.
  • Isolating a subnet class from obviously prohibited network ranges.

They are generally not the best primary mechanism for tier-to-tier access control because:

  • They cannot reference security groups.
  • Dynamic task and Pod IPs make CIDR rules brittle.
  • Load balancers, NAT, and operating systems use ephemeral ports.
  • A small mistake can block return traffic and resemble an application timeout.

A pragmatic policy is:

Subnet tierNACL postureMain protection mechanism
Public ingress/egressExplicitly associated NACL; optionally deny known hostile ranges; carefully allow required listener and return trafficWAF, ALB security group, workload security groups
Private applicationBroad internal and required return-path allowances; do not encode workload identity hereService security groups and egress architecture
Isolated dataExplicit internal-only guardrails if required by policy, tested thoroughlyNo default route plus database security group rules
Endpoint subnetPermit required TCP paths and return trafficEndpoint security group, endpoint and IAM policies

If you use restrictive NACLs, account for ephemeral ports in both directions. This is especially important for ALB-to-target traffic, NAT return traffic, and outbound HTTPS connections. In a production change review, a NACL modification that lacks an explicit return-path analysis should be treated as high risk.


Failure analysis: what happens when an AZ fails?

A multi-AZ diagram is not sufficient. State what continues to work and what must be tested.

FailureExpected behavior in this designRequired verification
One application AZ failsLoad balancer sends new requests to healthy targets in remaining AZs; ECS or EKS replaces capacity according to service configurationLoad test remaining AZ capacity; validate health-check convergence and autoscaling limits
One NAT Gateway or NAT AZ path failsWorkloads in that AZ may lose non-endpoint internet egress; workloads in other AZs retain their local NAT pathsEnsure each app subnet points to same-AZ NAT; prove critical AWS calls use endpoints rather than NAT
S3 or Secrets Manager call needed during an internet-egress incidentEndpoint-enabled workload continues through the AWS private path, assuming endpoint capacity and policy are healthyTest with NAT route disabled; validate private DNS resolution
Database subnet route table is modified accidentallyNo internet path exists unless a default route is explicitly introducedTerraform policy checks, route-table drift detection, change approval
A compromised API task attempts database access outside its roleSecurity group permits only its defined database port and endpoint path; IAM and database credentials further constrain accessTest deny cases, not only successful connectivity

The central operational lesson is that a healthy service in AZ A should not depend on a NAT Gateway, endpoint ENI, database endpoint, or route table path located only in AZ B.

For critical exchange services, design so that loss of general internet egress does not stop safe order cancellation, internal risk checks, or reconciliation. If external dependencies are unavailable, move to a defined degraded mode rather than allowing an uncontrolled accumulation of retries and connection exhaustion.


A concise architecture-defense answer

If asked, “How would you design the VPC?” a strong answer can sound like this:

“I would create a Region-level VPC spanning three Availability Zones, with public ingress and egress, private application, and isolated data subnets in each AZ. The internet-facing load balancer and one NAT Gateway per AZ reside in public subnets. ECS tasks or Kubernetes workloads run without public IPs in private subnets, and databases have no default route to NAT or the Internet Gateway.

“Each application subnet uses a route table pointing only to its same-AZ NAT Gateway for approved external egress. I would add Gateway Endpoints for S3 and DynamoDB where used, and Interface Endpoints in multiple AZs for Secrets Manager, ECR, CloudWatch Logs, STS, KMS, and SSM as required. That reduces NAT dependency for critical AWS calls.

“Security groups provide service-level segmentation: load balancer to API service, API and worker services to database, and workloads to endpoints, each on specific ports. I would use NACLs only as coarse subnet guardrails because they are stateless and unsuitable for expressing dynamic service identity. Finally, I would test AZ failure, endpoint-only operations, route-table changes, DNS behavior, and egress-policy failure as part of production readiness.”

That response states the topology, explains why it is resilient, and makes the security and cost trade-offs explicit.


Key takeaways

A defensible multi-AZ VPC design is organized by both trust boundary and failure domain:

  • Keep public ingress and NAT in public subnets; keep workloads private; keep databases and high-value state isolated without default internet routes.
  • Use one NAT Gateway per workload AZ and route each private subnet to its local NAT Gateway. Avoid hidden cross-AZ egress dependencies.
  • Use Gateway Endpoints for S3 and DynamoDB, and Interface Endpoints for supported AWS APIs that critical private workloads need.
  • Treat NAT as address translation and controlled source addressing, not as a complete egress-security control.
  • Use security groups as the stateful, identity-oriented microsegmentation layer. Use NACLs sparingly as stateless subnet guardrails.
  • Validate the design through failure scenarios, not only through a successful deployment.

Next, you will decide how traffic should enter and be protected at the edge: when to use Route 53, CloudFront, WAF, API Gateway, an Application Load Balancer, or a Network Load Balancer for differing latency, availability, and security requirements.

Can't find a good explanation? Sign up and we'll make it for you

Sign up