aws-enterprise-network is a lab built to practise the networking patterns that show up in real enterprise AWS accounts: multi-VPC design, cross-region Peering, a simulated Site-to-Site VPN, certificate-based Client VPN, Transit Gateway with selective route-table isolation, and PrivateLink for exposing a service without opening it to the internet. All of it works, end to end, and it's documented in the repo.

But "all of it works" undersells the project, because getting there meant sitting with three real problems that had nothing to do with networking theory and everything to do with how AWS actually behaves in practice. This is that part of the story.

An account restriction that took an AWS Support escalation to clear

The PrivateLink piece needed an internal Network Load Balancer. Creating it failed immediately:

OperationNotPermittedException: This AWS account currently does not support creating load balancers.

The account was on the AWS Free Plan at the time, so the obvious theory was a plan-tier gate. I upgraded to a paid support plan — which did fix a separate, confirmed restriction on CloudFront distribution creation — and assumed the same upgrade would clear the load balancer restriction too, since both looked like they came from the same account-tier gating.

They didn't. To retest cleanly, I tore down the environment entirely (it had also been getting expensive to keep running while I built out the VPN and Transit Gateway pieces) and rebuilt enet-vpc-a from scratch specifically to retry NLB creation. Same exact exception. The plan upgrade had done nothing for this particular restriction.

The actual fix took a support case, opened via live chat, escalated internally, and resolved seven days later with AWS Support confirming that Elastic Load Balancing access had been manually approved for the account in eu-west-2. Worth noting: an earlier case about the same underlying account state had sat unassigned for over a week, almost certainly miscategorized and routed to the wrong queue — filing a second, better-categorized case is what actually got it moving. The root cause was an account-level approval gate, not anything I could have fixed by clicking around the Console differently.

Terminal showing a curl request to the PrivateLink endpoint returning a healthy response from the web instance
The payoff, once the NLB restriction cleared: a consumer VPC reaching a service through PrivateLink with no peering and no public exposure.

A Console bug that silently hid the certificate I needed

Setting up the Client VPN endpoint, the Console's "Server certificate ARN" dropdown only ever offered the client certificate — never the server one, regardless of region, VPC selection, or a fresh browser session. There was no error, no validation message, just a dropdown quietly missing the option I needed.

The Console never explained why. The AWS CLI did: attempting the same operation returned an explicit error that the certificate "does not have a domain." The original server certificate had been generated via easy-rsa with a bare Common Name (server), no domain component — and ACM/Client VPN silently excludes certificates like that from the server-certificate dropdown rather than surfacing a validation error anywhere in the UI.

Fixed by regenerating the certificate with a domain-style CN (server.domain.tld), reimporting it into ACM, and creating the endpoint via CLI instead of fighting the wizard. Connected on the first try afterward — openvpn reported "Initialization Sequence Completed" with the correct routes pushed.

A security warning that turned out to be a false positive — and why I left it alone

After adding a second Availability Zone to the NLB (AWS recommends spanning at least two for fault tolerance), the Console kept showing a "Reachability may be impacted" warning on the original subnet — nowhere on the new one. Clicking in, the complaint was about the subnet's Network ACL: specifically, that the outbound rule for port 80 didn't allow 0.0.0.0/0.

It doesn't, on purpose. During an earlier security pass I'd scoped that outbound rule to 10.100.0.0/16 instead of leaving it wide open, precisely because the traffic never needs to leave that range — the target it's reaching is inside that same CIDR. The rule already covers the real destination; the Console's advisor just checks for an unrestricted allow rule rather than evaluating whether a narrower one already covers where the traffic is actually going. The curl test that had already run through that exact subnet moments earlier confirmed nothing was blocked in practice.

I left the NACL as originally scoped instead of loosening it to silence a static-analysis warning with zero functional benefit. Widening a deliberately narrow security control to make an automated advisor stop complaining isn't a trade worth making, and it's the same instinct behind the IAM finding in the same project — more on that below.

Terminal showing 100% packet loss when pinging an isolated VPC across Transit Gateway, confirming route-table isolation works
Transit Gateway with a separate, empty route table for one VPC — confirmed isolated (100% packet loss) while the default-route-table VPCs stay reachable.

The part I'd rather not have found, and documented anyway

A deliberate IAM audit on this project turned up something unflattering: the identity used for all Console and CLI work had AdministratorAccess attached, applied to every day of work rather than a policy scoped to what the project actually needed. Full account-wide permissions for a single-person learning account is a low-severity finding in practice, but it isn't least-privilege, and pretending otherwise in the writeup would have defeated the point of doing the audit at all.

The fix is drafted, not yet applied: a scoped custom policy — enet-scoped-policy.json — covering exactly the networking, compute, load-balancing, and monitoring actions this project has used, a region guard limiting the blast radius to the two regions actually in use, resource-scoped PassRole conditions, and explicit denies on IAM user/group/policy management so this identity can rotate its own credentials but can't create other users or escalate its own privileges. A pre-apply review caught a real gap in the first draft too — a region-restriction Deny statement exempted global services like AWS Support and Route 53 from the region lockdown without ever actually granting them anywhere, which would have cut off Support Center access with a live case open. Fixed before it became a problem instead of after.

Why this is the part worth reading

Anyone can follow a networking tutorial to a working VPC. What doesn't show up in the tutorial is an account-level restriction that requires escalating past a miscategorized support ticket, a Console bug with no error message pointing at the actual cause, or a security advisory that's technically wrong and needs to be understood well enough to override it deliberately rather than either blindly obeying or blindly ignoring it. That's the troubleshooting instinct this project was actually built to demonstrate — and it's why the real blockers are documented in docs/blockers.md instead of quietly edited out of the final repo.