AWS Cloud WAN series · Part 14 of 17

AWS Cloud WAN: Multi-Account Infrastructure-as-Code

Fourteenth in the AWS Cloud WAN series, and the one where the architecture finally meets the org chart. Cloud WAN's biggest payoff shows up in the exact environment that makes it hardest to run as code: many accounts, many Regions, many teams. Here's how to split ownership so one team owns the core network and policy, every other account self-serves its own attachments, and a bad routing change gets caught in CI before it ships — with every claim sourced to AWS docs.

TL;DR

Run Cloud WAN at org scale by splitting it along ownership, not along Regions. The networking team owns one Terraform workspace — global network, core network, and policy — and shares the core network across the organization with AWS RAM. Every workload account runs its own templated workspace that creates VPCs and attachments and tags the attachment so the central attachment policy files it into the right segment automatically. AWS's own guidance is to decouple these into separate stacks for independent lifecycle; the one trap that bites everyone is that the RAM share must be initiated from us-east-1, not from Cloud WAN's Oregon home Region.

Design it this way

  • One workspace owns core network + policy (networking team); separate workspaces own VPCs + attachments (each account).
  • Share the core network org-wide via RAM, from us-east-1.
  • Make Workspace 2 a template: tag the attachment, let the policy place it.
  • Gate every policy change in CI — the change set is never deployed automatically.

Don't do this

  • Don't create the core network and its attachments in one workspace.
  • Don't share from the Oregon home Region — other Regions won't see it.
  • Don't tag the VPC resource and expect mapping — tags must be on the attachment.
  • Don't make the networking team touch a thing to onboard a new account.

Article 13 introduced Cloud WAN in Terraform and stated one rule almost in passing: don't deploy the core network and the VPC attachments in the same workspace. This article is that rule, fully developed — why the split exists, how you share the core network so other accounts can even reach it, how an account onboards itself without a central change, and how you stop a one-line policy edit from rerouting your entire global network. The shape that falls out — central policy, distributed attachment — is the operational reason Cloud WAN is worth its premium for a large estate.

Figure 1 · Who owns what Split ownership along the workspace boundary, not the Region OWNS · NETWORKING TEAM OWNS · EACH WORKLOAD TEAM Network / central account Workspace 1 · one source of truth Global network + core network Core network policy (segments, shares) RAM share (initiated in us-east-1) CI gate on every policy change Pays for the CNEs; one policy, globally. Workload accounts (many) Workspace 2..N · one template each Their own VPC(s) and CIDRs Their own Cloud WAN attachments Tags on the attachment (segment =...) Acceptance only on sensitive segments Pays for its own VPC attachment + data. AWS RAM
The split is an ownership boundary: one team holds the core network and the single policy; every workload team self-serves attachments and tags. RAM is the only thing that crosses it.

Why the core network and its attachments can't share an owner

Article 13's rule was blunt: don't put the core network and the VPC attachments in the same Terraform workspace. The reason most often given by practitioners is a dependency race — within one apply, Terraform can try to create attachments before the core network and its policy have settled, and that ordering is hard to express reliably. I'd flag that the race-condition framing is practitioner lore, not something AWS documents; treat it as the intuition, not the citation.

What AWS does document is the conclusion, and it's the one that matters: decouple the global resources from the regional VPCs into separate stacks. The maintained aws-ia/cloudwan module README says to create the global network and core network in a different module definition than the Central VPCs precisely to decouple them; AWS's blueprints generalize it to "separate network infrastructure, workload VPCs, and inspection resources" so each has its own lifecycle. The two-workspace split is the minimum viable form of that discipline.

The payoff isn't just dodging a race. It's independent lifecycle (Figure 1). The networking team evolves the policy without waiting on a dozen workload teams to run apply; a workload team attaches a new VPC without ever touching — or having permission to touch — the core network. That division also lines up with billing: the core-network owner pays for the per-Region CNEs, and each VPC-owning account pays for its own attachment and its own data processing. Ownership, blast radius, and the invoice all break along the same line. That's not a coincidence; it's the whole reason to draw the boundary there.

How every account gets to see one core network — RAM, and the us-east-1 trap

Here's the structural fact that makes multi-account Cloud WAN possible at all: a VPC in account B can't attach to a core network owned by account A until account A shares it with AWS Resource Access Manager. RAM is the linchpin — without the share, the resource doesn't exist as far as account B is concerned.

You can share with individual accounts or with the whole AWS Organization / OUs, and org-wide is the scalable choice: new accounts inherit access without a per-account RAM grant. A shared core network supports VPC attachments and TGW route-table (peering) attachments from the recipient accounts — recipients can create, get, and delete their attachments, but they can't modify the core network itself.

The one that catches everyone: you must initiate the RAM share from N. Virginia, us-east-1, so that every other Region can see the global resource. That is not the same Region as Cloud WAN's home Region, which is always US West (Oregon), us-west-2 regardless of your provider config. Two different Regions, for two different reasons. Share from Oregon (or from wherever your pipeline happens to run) and the share silently succeeds while the core network stays invisible everywhere else — the kind of bug that costs an afternoon because nothing errors.

Once shared, the magic is that nothing about a workload account's attachment is special-cased. Its attachment lands in the core network and is mapped to a segment by the central attachment policy (Article 4) based on the attachment's tags — no manual association, and the same governance applies no matter which account it came from. The boundary you designed in the segment matrix (Article 3) enforces uniformly across every account, because the policy enforces it, not per-account wiring. Figure 2 shows the shape: one core network, shared once, with two accounts' VPC attachments falling into different segments purely on their tags.

Figure 2 · One core network, shared to many accounts Network / central accountWorkload account A (prod)Workload account B (dev)first-match -> segmenttag segment=prodRAM sharetag segment=devRAM shareCore network(us-west-2 home)AttachmentpolicyAttachmentsegment=prodProd VPCAttachmentsegment=devDev VPC
The network account shares one core network via RAM; each workload account's VPC attachment maps into a segment by its own tag — no central change per account.

How a new account onboards itself — the templated attachment workspace

With the core network shared, Workspace 2 becomes a template that each account stamps out. The pattern, drawn straight from the maintained module:

That's what makes onboarding a near-trivial operation (Figure 3): stamp the template, tag correctly, and the workload joins the right segment automatically — subject to acceptance on sensitive segments, where the attachment sits in Pending attachment acceptance until an owner approves it. The networking team never makes a change to bring a new account online. The attachment policy already anticipated it; the new account just matches a rule that was written months ago.

Two details from earlier articles bite hardest in exactly this multi-account, templated setting:

Tag the attachment, not the VPC. The single most-missed rule in Cloud WAN: the attachment policy analyzes "the tags associated with the attachment, and not the tags associated with the VPC resource." In a templated module this is a real footgun, because Terraform makes it easy to tag the VPC. In the maintained module, tags placed under the core_network subnet type are the ones applied to the attachment — put your segment-mapping tags there, and verify on the attachment object, not the VPC. Rules are evaluated lowest-number first and first match wins, so a too-broad early rule can quietly swallow an attachment you meant for a later one.

Use AZ IDs, not AZ names. AWS randomizes the AZ-name-to-physical mapping per account — us-east-1a is a different physical zone in account A than in account Z. Place attachment subnets by the stable AZ ID (e.g. use1-az1, identical in every account) so attachments from different accounts land in the same physical zone. This is critical for shared-services and inspection segments, where cross-account flows that "look" same-AZ but aren't will cost you latency and, with appliance mode, correctness.

Figure 3 · Onboarding a new account Stamp the template → tag → the policy files it — no central change 1 · Copy template reusable Workspace 2 module, per account 2 · Create VPC(s) own CIDRs, subnets by AZ ID 3 · Attach VPC attachment to the shared core 4 · Tag attachment segment = prod (on the attachment) 5 · Central attachment policy matches the tag → places it in the segment first-match-wins · acceptance required only on sensitive segments Networking team: no change
The whole onboarding is workload-owned (green) right up to the tag; the only central component (blue) is the policy that was already written. New account, zero networking-team toil.

How you stop one line of HCL from rerouting the planet — CI on the policy

The policy is a single document that controls global routing, so a bad change has a broad blast radius — which is exactly the argument for catching it before it goes live. The version-and-rollback safety net (Article 2) saves you after the fact; CI saves you before.

And you get a real assist from the platform here: a new policy version is never deployed automatically. Every change generates a numbered version, only one is LIVE at a time, and AWS gives you a change set with explicit states — Pending generationReady to execute ("verified with no issues... can be deployed as the new LIVE policy") or Failed generation, then a human applies it. Rollback is restoring an out-of-date version — effectively one action. That built-in gate is the documented pre-deploy verification surface; build your pipeline to sit in front of it (Figure 4).

What I'd wire into the pipeline for Workspace 1:

One honest caveat. The specific assertion set people reach for — "prod and non-prod share nothing, sandbox is isolated, PCI shares only what it's allowed to" — and the idea of applying the policy to a throwaway core network first are sensible engineering, but they're my recommendation and the community's, not something AWS publishes a recipe for. Silverflow confirms teams encode such checks; it doesn't hand you the rules. So lean on the documented change-set gate as the backstop, and write the assertions that encode your matrix.

Figure 4 · The policy CI gate (Workspace 1) A bad routing change should die in CI — not in production PR policy HCL edit Render policy diff reviewer sees every change Assert vs segment matrix custom checks (no native lint) Generate change set Pending → Ready / Failed Ready to execute? Rejected failed gen / bad assert no Human approve apply the version yes LIVE policy one version live rollback = restore an out-of-date version
The platform already refuses to auto-deploy a policy version; CI's job is to render the diff, assert your matrix, and only let a Ready to execute change set reach a human — with one-action rollback behind it.

Who owns what at org scale — the reference topology

Putting the pieces together into one operational picture:

The networking team manages one policy; every other account self-serves attachments within the guardrails that policy enforces. That division — central policy, distributed attachment — is the operational shape that makes Cloud WAN worth its premium for a large organization. It's also the shape that doesn't fall apart at forty accounts the way a hand-wired hub-and-spoke does.

A scaling caveat worth saying out loud. "Self-serve attachments" is bounded by the policy's own limits — notably the hard ceiling of 40 segments per core network, not adjustable, which inspection NFGs also draw from (Article 3). Distributed attachment scales freely; the segment vocabulary those attachments map into does not. Design the matrix to stay coarse so the org can keep onboarding into it.

What to actually do

If you take one thing from this article, make it the boundary. Draw the line between the core network and its attachments, and let everything else follow it — ownership, permissions, blast radius, and the bill all break cleanly along that same seam.

Concretely: stand up Workspace 1 in a dedicated network account (core network + policy), share the core network org-wide via RAM from us-east-1, and make Workspace 2 a parameterized template that every account stamps out — tagging the attachment, never the VPC, and placing subnets by AZ ID. Put a CI gate in front of the policy that renders the diff and asserts your segment matrix, and trust the platform's change-set gate as the backstop that won't auto-deploy. Onboarding a new account should be a pull request in that account's repo and nothing in yours.

You can now build and operate Cloud WAN across an organization as code. But building it is only half the job — you have to run it, watch it, and fix it when traffic misbehaves. Article 15 turns to observability and troubleshooting: the CloudWatch metrics Cloud WAN exposes (including per-AZ), where its visibility differs from TGW flow logs, reading route tables in the console, PMTUD behavior, and the common failure modes — dropped traffic from missing routes, asymmetry, appliance-mode misconfiguration — with how to diagnose each.

Sources

  1. AWS — Share your Cloud WAN global network resources (RAM): the share must be initiated from N. Virginia (us-east-1) so all other Regions can see the global resource; share to accounts or to the whole Organization/OUs; recipients can create/get/delete attachments but not modify the core network. docs.aws.amazon.com/.../cloudwan-share-network.html
  2. AWS — What is AWS Cloud WAN: the home Region is US West (Oregon)/us-west-2 and can't be changed. docs.aws.amazon.com/.../what-is-cloudwan.html
  3. AWS — Terraform aws-ia/cloudwan module README + AWS Cloud WAN blueprints: decouple the global network/core network/policy from the regional Central VPCs into separate stacks for independent lifecycle. github.com/aws-ia/terraform-aws-cloudwan
  4. AWS — Terraform aws-ia/cloudwan/aws module registry: central VPC types (inspection, egress, ingress, shared_services,...); tags under the core_network subnet type are applied to the attachment. registry.terraform.io/modules/aws-ia/cloudwan/aws/latest
  5. HashiCorp — aws_networkmanager_core_network provider docs: the bootstrap trio (base_policy_document, base_policy_regions, create_base_policy) and applying the real LIVE policy via aws_networkmanager_core_network_policy_attachment. registry.terraform.io/.../networkmanager_core_network
  6. AWS — Attachment policies for the core network: the attachment's own tags are analyzed, not the VPC resource's; rules evaluate lowest-number first and stop on first match. docs.aws.amazon.com/.../cloudwan-policy-attachments.html
  7. AWS — Working with Availability Zone IDs (RAM): AZ names are randomized per account; use the stable AZ ID (e.g. use1-az1) for cross-account placement. docs.aws.amazon.com/ram/.../working-with-az-ids.html
  8. AWS — Create a Cloud WAN policy version: every change creates a numbered version; only one is LIVE; "a policy version is never implemented automatically"; change-set states (Pending generation, Ready to execute, Failed generation); rollback = restore an out-of-date version. docs.aws.amazon.com/.../cloudwan-create-policy-version.html
  9. AWS — How Silverflow modernized network operations by combining AWS Cloud WAN and DevOps (blog): no native Cloud WAN policy lint, so a custom check_policy_compliance parses the definitions and fails the build; gated by CODEOWNERS with human approval. aws.amazon.com/blogs/.../how-silverflow-modernized-network-operations...
  10. AWS — Cloud WAN peerings: a shared core network supports TGW route-table attachments; peering is to a TGW in the same Region (BGP-only). docs.aws.amazon.com/.../cloudwan-peerings.html
  11. AWS — Cloud WAN pricing: billing split — the core-network owner pays for CNEs; the VPC-owning account pays for its own VPC attachment and its data processing. aws.amazon.com/cloud-wan/pricing
  12. AWS — Create a Cloud WAN attachment: the eight lifecycle states, including "Pending attachment acceptance" when require-attachment-acceptance is true. docs.aws.amazon.com/.../cloudwan-create-attachment.html
  13. AWS — Cloud WAN quotas: "Segments per core network" = 40, Adjustable = No. docs.aws.amazon.com/.../cloudwan-quotas.html