Skip to content

Network Architecture & Segmentation (production)

Purpose. Shows how production is separated from the internet and from everything else, and which paths are allowed between zones. Drawn from the OpenTofu that defines the network (SoonHQ/soon-terraform, master at f23dcd2, 2026-09-21) and checked against the live DNS and TLS endpoints on 2026-09-25, not from intent. Where the design has a known gap, the gap is shown, not hidden.

1. Diagram

Internet — customers' browsers HTTPS only Cloudflare edge DNS · CDN · WAF · TLS termination Cloudflare Pages: app.soon.works (static web app — no customer data) API hostname — direct to AWS soon-server-alb-production.soon.works resolves straight to the ALB, not through Cloudflare (gap, S-426) AWS eu-west-1 · production account 742816139593 · production VPC Public subnets Application Load Balancer 443/80 from anywhere · TLS 1.2+, CBC suites refused 2 × NAT gateway fixed egress IPs Internet gateway public subnets only Private subnets — no public IPs, no inbound from the internet ECS Fargate services soon-server API · solver · scheduled tasks inbound: container port from the ALB only RDS MySQL 8.4 (Multi-AZ) in the default VPC, via peering not publicly accessible · KMS · tasks only ElastiCache Redis in-VPC cache and queues from service tasks only outbound Engineer access IAM Identity Center (MFA) → SSM Session Manager → database Separate account 404379474355 (Soon-LogArchive) org CloudTrail · evidence store · isolated backup vault

Red, dashed: a known gap, described in §4. The database box is drawn in the data tier it serves; physically it is in the default VPC (§2).

2. Zones

Zone What sits there Inbound allowed Defined in
Cloudflare edge DNS, CDN, WAF, TLS for app.soon.works; Cloudflare Pages hosts the static web application HTTPS from anywhere Cloudflare (dashboard)
Public subnets Application Load Balancer, two NAT gateways, internet gateway ALB: 80 and 443 from anywhere; nothing else modules/alb, modules/network
Private subnets: compute ECS Fargate services (API, solver, scheduled tasks); tasks get no public IP (assign_public_ip = false) Container port from the ALB's security group only modules/fargate-service, envs/prod/runtime
Data ElastiCache Redis in the production VPC's private subnets. RDS MySQL rds-soon-soon-prod (Multi-AZ, KMS-encrypted, PubliclyAccessible = false, 30-day backups) is in the account's default VPC (172.31.0.0/16), reached from production over the VPC peering connection soon-prod-app-to-default-rds (verified 2026-10-21) Database: 3306 from the production service tasks' security group (plus four stale public addresses to remove, see §4); engineers only through SSM Session Manager. Redis: from the service tasks only envs/prod/stateful, modules/redis; the database predates the OpenTofu network
Log-archive account Organisation CloudTrail, audit-evidence store, isolated backup vault No network path from production; protected by the ProtectSecurityLogs SCP AWS Organizations

3. Separation from other environments

  • Development runs in its own VPC with its own load balancer and database. There is no peering or shared network path to production.
  • Staging runs on Azure and holds no production data (confirmed 2026-09-09); its AWS replacement is written but not yet applied (S-496).
  • connect.soon.works (integration OAuth service) runs on Google Cloud in europe-west4 and is called by the backend over HTTPS. Its migration to AWS is tracked in Linear.
  • Outbound traffic from production leaves through the two NAT gateways, whose fixed addresses are what customer telephony integrations allowlist.

4. Known gaps

Gap Effect Tracked
The API hostname resolves directly to the ALB rather than through Cloudflare Cloudflare's WAF, bot management and rate limiting cover the web application but not the API, including its login endpoints. The application's own rate limiter (60 requests/minute per IP on password routes, plus per-account limits) is what stands in front S-426
The production database is in the default VPC, whose subnets route to an internet gateway, reached over peering. Only PubliclyAccessible = false keeps it off the internet No public endpoint today (verified 2026-10-21). One mis-set flag would expose it; its security group also still lists four public addresses Annual Firewall Rule Review 2026 (ISMS-FORM-A08-20-2) findings 2–3
The production API tasks' security group allows the container port from anywhere, not only from the load balancer Not reachable from the internet (private subnets, no public IP, no IPv6), but reachable from anything inside the production or peered VPC ISMS-FORM-A08-20-2 finding 1
A development solver load balancer (soon-seer-alb-dev) runs in the production VPC Development and production are not fully separated at network level for this service ISMS-FORM-A08-20-2 finding 5
AWS WAF on the ALB not yet verified If absent, there is no managed firewall layer in front of the API at all S-426
Legacy security-groups/ and seer/ modules in the repository allow a container port from 0.0.0.0/0 The live check of 2026-10-21 found the production task group open in exactly this way (ISMS-FORM-A08-20-2 finding 1), and nine unattached groups open to the internet (finding 4). Delete the legacy modules and the orphaned groups ISMS-FORM-A08-20-2

Change log

Version Date Author Change
0.1 2026-09-29 ISMS First version, for SOC 2 checklist row 45 (CC6.6), after the auditor's review asked for a network diagram. Drawn from soon-terraform master at f23dcd2 and live DNS/TLS checks on 2026-09-25. For Thomas to verify before approval.
0.2 2026-10-21 ISMS Corrected from the live AWS check for the annual firewall review: the production database is in the default VPC, reached over peering, not in the production VPC's private subnets; added the open task security group and the development solver in the production VPC as known gaps. For Thomas to verify before approval.