Skip to content

Network Topology

This page covers the network topology decisions set out in RAG001, RAG010, and RAG011.


VPC layout

QA and Prod each own one VPC in us-east-1. The two VPCs are structurally identical and not peered. Aurora Serverless v2 places a cluster instance in each AZ covered by the subnet group.

EnvironmentVPC blockSubnet A (us-east-1a)Subnet B (us-east-1b)
QA10.10.0.0/1610.10.1.0/2410.10.2.0/24
Prod10.20.0.0/1610.20.1.0/2410.20.2.0/24

Blocks are non-overlapping RFC 1918 /16 prefixes. Specific values are set in each environment’s Terraform root (infra/environments/qa/ and infra/environments/prod/).

Each subnet has a local route entry only (10.x.0.0/16 local). There is no 0.0.0.0/0 or ::/0 entry. No Internet Gateway is attached. No NAT Gateway or VPC endpoint of any kind is provisioned.

Resource typeCountNotes
aws_vpc1 per envDNS hostnames enabled; DNS support enabled
aws_subnet (private)2 per envOne per AZ; no map_public_ip_on_launch
aws_db_subnet_group1 per envSpans both subnets; used by the data module
aws_security_group (Aurora)1 per envInbound from VPC CIDR on 5432

Resources absent from the module: aws_internet_gateway, aws_nat_gateway, aws_eip, aws_route_table with a public default route, aws_vpc_endpoint of any kind. The absence is intentional per RAG010.

Aurora security group

DirectionProtocolPortSourcePurpose
InboundTCP5432VPC CIDR (intra-VPC)PostgreSQL access from within the VPC
OutboundAllAll0.0.0.0/0AWS default; no in-VPC destination exists to reach

The inbound rule admits nothing today because no other resource runs inside the VPC. Aurora is also reachable via the RDS Data API service endpoint, an AWS-managed HTTPS path that does not traverse the security group’s inbound rules. That path is governed by IAM (rds-data:ExecuteStatement on the cluster ARN) per RAG011.

No custom NACLs are provisioned. The default NACL applies; given the route tables carry no public routes, the NACL layer adds no meaningful control.


Service placement

Aurora is the only resource inside the VPC. Every other service runs outside the VPC and is reached from Lambda over public AWS endpoints. Lambda functions have no VPC attachment (vpc_config is not set).

Inside VPC

ServiceHow reached
Aurora Serverless v2Subnet group spanning two AZs. RDS Data API (HTTPS, SigV4) from outside VPC; TCP/5432 unreachable from Lambda

Outside VPC

ServiceHow reached
API LambdaLambda execution environment. Invoked by API Gateway over AWS-managed integration
Authorizer LambdaLambda execution environment. Invoked by API Gateway on every authenticated request
Ingestion LambdaLambda execution environment. Invoked by operator or CI
API Gateway HTTP APIAWS-managed regional. Public HTTPS endpoint; TLS terminated here
CloudFront + S3 (SPA)AWS-managed global CDN + regional object store. No VPC association; S3 access via Origin Access Control
AWS Bedrock (Titan, Haiku-class)AWS-managed regional endpoint bedrock-runtime.us-east-1.amazonaws.com; IAM-authed HTTPS. The request is issued to that regional endpoint, but generation runs through a cross-region inference profile, which may execute it in any region in the us. group. The Lambda’s IAM policy grants foundation-model ARNs for every region the profile can route to (RAG007). Prompt content is therefore not confined to us-east-1
Secrets ManagerAWS-managed regional. secretsmanager.us-east-1.amazonaws.com; IAM-authed HTTPS; read at cold start
CloudWatch Logs and MetricsAWS-managed regional. Public endpoint; Lambda Powertools emits structured logs and EMF metrics
X-RayAWS-managed regional. Public endpoint; Lambda Powertools instruments traces
RDS Data API endpointAWS-managed service plane. HTTPS; IAM-authed; application path into Aurora that requires no TCP from inside the VPC

Auth and authz boundary. The Authorizer Lambda creates an authorization boundary at the API Gateway layer. API Gateway invokes it before routing any request to the API Lambda. The Authorizer Lambda calls Aurora via the RDS Data API to validate the bearer token against the key store. If the token is absent, expired, or invalid, API Gateway returns 401 or 403 and the API Lambda is never invoked. This boundary is documented as B1 in the trust boundary inventory.

On “public endpoints.” Every AWS service listed above (Bedrock, Secrets Manager, CloudWatch, X-Ray, RDS Data API) is reached by Lambda via an HTTPS endpoint with a public DNS name. These calls travel over the AWS networking fabric; they do not traverse a home-internet path, but they do use public IP space. No VPC gateway endpoint and no PrivateLink interface endpoint is provisioned. The cost rationale is in RAG010.


Data-flow paths

Query path

LikeC4 dynamic view could express this, but a sequence diagram makes the Authorizer interception and the two-Bedrock-hop order clearer in a single diagram. Using mermaid sequenceDiagram as the LikeC4 fallback per the diagram rule.

BedrockAurora (RDS Data API)API LambdaAuthorizer LambdaAPI Gateway HTTP APICloudFront + S3BrowserBedrockAurora (RDS Data API)API LambdaAuthorizer LambdaAPI Gateway HTTP APICloudFront + S3BrowserHTTPS (TLS at edge)SPA assets (OAC-signed S3 origin)POST /query (HTTPS, TLS at API GW)invoke (bearer token)ExecuteStatement / token lookup (SigV4, HTTPS)token valid / invalidallow or deny policyinvoke (on allow)embed query (SigV4, HTTPS)embedding vectorsimilarity search (SigV4, HTTPS)top-k chunksgenerate answer (SigV4, HTTPS)answer textanswer + citations

TLS is terminated at API Gateway for the API call and at the CloudFront edge for SPA asset delivery. Lambda-to-service calls use HTTPS with SigV4 request signing. The API Gateway-to-Lambda invocation is AWS-managed and does not pass through a user-controlled network path.

The RDS Data API hop: Lambda sends an HTTPS ExecuteStatement request to rds-data.us-east-1.amazonaws.com. AWS routes that call to the Aurora cluster through its own service plane. The call does not originate from inside the VPC, and the Aurora security group’s TCP inbound rules are not involved. Authorization is IAM (rds-data:ExecuteStatement on the cluster ARN), enforced by AWS before the call reaches the cluster.

Ingestion path

LikeC4 dynamic view could express this. Using mermaid sequenceDiagram for the same reason as the query path: the local-vs-Lambda conditional and the external Hugging Face hop are cleaner in a sequence diagram than in a LikeC4 dynamic view.

Hugging Face HubBedrockAurora (RDS Data API)Postgres in Docker (local only)Operator / CI runnerHugging Face HubBedrockAurora (RDS Data API)Postgres in Docker (local only)Operator / CI runneralt[Local run][AWS run (Lambda or CI)]HTTPS corpus downloadneural-bridge/rag-dataset-12000embed chunks (SigV4, HTTPS)embedding vectorspsycopg / local socketExecuteStatement upsert (SigV4, HTTPS)

Ingestion runs outside the VPC whether executed locally or as a Lambda invocation. CI runners are GitHub-hosted and reach AWS via an OIDC-federated IAM role; they never enter the VPC. See RAG011 for the data-access contract difference between operator tooling and the application Lambda path.

Observability path

All observability traffic leaves Lambda directly to public AWS service endpoints. No VPC-side flow logs and no network tap are provisioned. The absence of VPC flow logs follows from RAG010: no ENIs emit traffic inside the VPC for flow logs to capture.


Cross-environment isolation

QA and Prod are separate VPCs in a single AWS account.

Isolation propertyMechanismLevel
Network-layer isolation between QA and ProdSeparate VPCs; no peering; no Transit GatewayNetwork
Data isolationSeparate Aurora clusters, Secrets Manager ARNs, S3 bucketsResource
IAM isolationSeparate Lambda execution roles scoped to per-env resource ARNsPolicy
Terraform state isolationSeparate S3 state keys; separate S3-native lock files (per-environment)Operational
Deployment gateQA auto-deploys; Prod requires manual approvalProcess

What is not isolated at the network layer, because separation is only account-level:

  • IAM namespace: a misconfigured IAM policy could grant cross-environment access. Per-env role ARNs and resource ARN conditions are the control, not network separation.
  • Account-level service quotas: Lambda concurrency, Bedrock model RPM, and API Gateway throttles are account-level. A runaway QA workload can consume quota that Prod depends on.
  • Bedrock model access: model availability and regional quotas are account-level, not per-VPC.
  • CloudFront ACM certificate ARNs: if a wildcard certificate covers both environments, its ARN is shared across them.
  • AWS Budgets alarms: billing is account-wide, and per-environment attribution depends on cost allocation tags.

The migration path to per-account isolation is documented in RAG001.


Failure modes

FailureAffected pathUnaffectedMitigation / notes
Single-AZ Aurora subnet lossRDS Data API calls during failover (~30-60 s)Lambda, API Gateway, CloudFront, BedrockAurora Serverless v2 auto-fails over to second AZ; Lambda-layer retries absorb brief window
Both AZs fail (regional Aurora outage)All /query requests return 500API Gateway, Lambda, CloudFront + S3 (SPA still served)No cross-region failover configured; accepted risk at demo scale
CloudFront edge PoP issueSPA asset load for affected usersAPI path (API Gateway is regional, not edge-distributed)Recovery outside operator control; no topology change resolves it
API Gateway throttle (burst limit)429 before Lambda is invokedAurora, Lambda execution env4XXError metric on API GW stage captures spike; POST /query has a route-level throttle at 1 req/s steady-state, burst 5, while ANY /{proxy+} is unthrottled, and it is recorded under Controls in place in the security assessment
Bedrock regional outage (us-east-1)Embedding and generation; all /query requests failAurora, API Gateway, Lambda invocation, CloudFrontNo cross-region failover; accepted risk
RDS Data API unavailabilityAll database calls from Lambda regardless of Aurora healthAurora TCP/5432 (unreachable from Lambda anyway)Known constraint of the chosen data-access contract per RAG011

Operational surface

Inspecting the VPC

# List VPCs by environment tag
aws ec2 describe-vpcs \
  --filters "Name=tag:Environment,Values=qa" \
  --query 'Vpcs[*].{VpcId:VpcId,CIDR:CidrBlock,State:State}'

# List subnets in a VPC
aws ec2 describe-subnets \
  --filters "Name=vpc-id,Values=<vpc-id>" \
  --query 'Subnets[*].{SubnetId:SubnetId,AZ:AvailabilityZone,CIDR:CidrBlock}'

# Confirm no Internet Gateway is attached
aws ec2 describe-internet-gateways \
  --filters "Name=attachment.vpc-id,Values=<vpc-id>"
# Expected: empty Attachments array

# Confirm no NAT Gateways in the VPC
aws ec2 describe-nat-gateways \
  --filter "Name=vpc-id,Values=<vpc-id>"
# Expected: empty, or only entries in deleted state

# Inspect Aurora security group inbound rules
aws ec2 describe-security-groups \
  --filters "Name=vpc-id,Values=<vpc-id>" \
  --query 'SecurityGroups[*].{GroupId:GroupId,Name:GroupName,Ingress:IpPermissions}'

# Confirm no VPC endpoints provisioned
aws ec2 describe-vpc-endpoints \
  --filters "Name=vpc-id,Values=<vpc-id>"
# Expected: empty

To confirm that no public path exists to the Aurora cluster: in the AWS Console, go to VPC > Reachability Analyzer. Because no Internet Gateway is attached, an analysis sourced from an internet gateway cannot be constructed. The more informative check is to verify that Lambda has no ENI inside the VPC:

aws lambda get-function-configuration \
  --function-name <env>-rag-api \
  --query 'VpcConfig'
# Expected: null or empty SubnetIds and SecurityGroupIds

Log groups

Log groupFields of interest
/aws/lambda/<env>-rag-apicold_start, xray_trace_id, RDS Data API client errors
/aws/lambda/<env>-rag-authorizercold_start, RDS Data API error on token lookup
/aws/lambda/<env>-rag-ingestionRDS Data API and Bedrock call durations
API Gateway access logs (if enabled)sourceIp, requestId, status, responseLatency

CloudWatch Logs Insights query to surface RDS Data API errors in the API Lambda log group:

fields @timestamp, @message
| filter @message like /rds-data|RDS Data API|ExecuteStatement/
| sort @timestamp desc
| limit 50

VPC Flow Logs are not enabled. No ENIs emit traffic inside the VPC today; see RAG010. If troubleshooting intra-VPC connectivity becomes necessary after a future architecture change, enable VPC Flow Logs on the VPC and publish to CloudWatch Logs or S3 before diagnosing.


When this page changes

This page must be updated when any of the following occur:

  • The reversal procedure in RAG010 fires: NAT Gateway, PrivateLink endpoints, or a new in-VPC workload is introduced. The subnet layout, route tables, security group rules, and data-flow paths all change.
  • RAG011 is superseded: the application data-access path to Aurora changes, which changes the query-path diagram and the service placement table.
  • A new AWS service is added to the application. Add it to the service placement table.
  • A second region is added. The single-region assumption in this document is pervasive.
  • The AWS account separation described as a migration path in RAG001 is executed. The cross-environment isolation section changes substantially.

Changes arising from RAG010 reversal must also update architecture/cost and trigger a re-review of the security assessment and trust boundaries.