Skip to content

Instantly share code, notes, and snippets.

@huynhbaoan
Last active December 26, 2024 09:08
Show Gist options
  • Save huynhbaoan/5db277e74ef8cfa664ff2defe177eb47 to your computer and use it in GitHub Desktop.
Save huynhbaoan/5db277e74ef8cfa664ff2defe177eb47 to your computer and use it in GitHub Desktop.
Below is an illustrative example of how you can structure and write the Terraform code for CloudWAN resources using modules. This is a sample layout and code—adjust names, variables, and values to fit your actual environment and CIDR blocks.
Note:
• The code below uses placeholder values. You will need to replace these with your actual values (VPC IDs, segment names, etc.).
• The CloudWAN functionality and resources used are based on current AWS provider capabilities (as of AWS provider v4.x).
• Policies and segment relationships must be defined carefully in the JSON documents. The policy code example is a starting point; you will need to customize it to reflect your routing rules.
• This code assumes you have already created VPCs and their subnets. The VPC attachments here will reference existing VPC IDs and subnets.
• The firewall code snippet is a placeholder to create a firewall VPC attachment and related resources. Actual firewall logic (like configuring AWS Network Firewall or third-party firewall appliances) would be handled separately.
Directory Structure
CloudWAN/
├── main.tf
├── variables.tf
├── outputs.tf
├── modules/
│ ├── cloudwan_core/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── outputs.tf
│ ├── cloudwan_segment/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── outputs.tf
│ ├── cloudwan_vpc_attachment/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── outputs.tf
│ ├── cloudwan_policy/
│ │ ├── main.tf
│ │ ├── policy.json.tpl
│ │ ├── variables.tf
│ │ └── outputs.tf
│ └── firewall/
│ ├── main.tf
│ ├── variables.tf
│ └── outputs.tf
├── nonprod/
│ ├── mel-cloudwan-policy.tf
│ ├── mel-vpc-attachment.tf
│ ├── syd-cloudwan-policy.tf
│ ├── syd-vpc-attachment.tf
│ ├── global-sdwan-seg.tf
│ ├── variables.tf
│ └── outputs.tf
└── prod/
├── mel-cloudwan-policy.tf
├── mel-vpc-attachment.tf
├── syd-cloudwan-policy.tf
├── syd-vpc-attachment.tf
├── direct-connect-seg.tf
├── variables.tf
└── outputs.tf
• main.tf at the top-level can define providers and global data sources if needed.
• nonprod/ and prod/ directories hold environment-specific .tf files that call modules to create attachments, policies, etc.
• Modules are in modules/ directory and contain reusable code.
Module: cloudwan_core
modules/cloudwan_core/variables.tf:
variable "core_network_name" {
type = string
description = "Name for the CloudWAN core network."
}
variable "tags" {
type = map(string)
default = {}
}
modules/cloudwan_core/main.tf:
resource "aws_networkmanager_core_network" "this" {
global_network_id = "<YOUR_GLOBAL_NETWORK_ID>" # Pre-existing global network ID
description = "Core network for CloudWAN"
tags = var.tags
}
modules/cloudwan_core/outputs.tf:
output "core_network_id" {
value = aws_networkmanager_core_network.this.id
}
You would call this module once at a global level (e.g., in main.tf at top level) if you haven’t created the core network yet.
Module: cloudwan_segment
Segments are typically defined in the core network policy. If you prefer to have a module that just outputs segment names (for consistency), you can do so, but note that segments themselves are not standalone resources; they are defined within the aws_networkmanager_core_network_policy resource’s JSON policy document.
modules/cloudwan_segment/variables.tf:
variable "segment_name" {
type = string
}
modules/cloudwan_segment/main.tf:
# This module might just return the segment name, as segments are defined in policy
output "segment_name" {
value = var.segment_name
}
modules/cloudwan_segment/outputs.tf:
# Already outputted in main.tf
You’ll integrate these segments into the policy module later by providing segment names as inputs.
Module: cloudwan_vpc_attachment
modules/cloudwan_vpc_attachment/variables.tf:
variable "core_network_id" {
type = string
}
variable "vpc_id" {
type = string
}
variable "subnet_arns" {
type = list(string)
}
variable "segment_name" {
type = string
}
variable "tags" {
type = map(string)
default = {}
}
modules/cloudwan_vpc_attachment/main.tf:
resource "aws_networkmanager_vpc_attachment" "this" {
core_network_id = var.core_network_id
vpc_arn = "arn:aws:ec2:${var.region}:${data.aws_caller_identity.current.account_id}:vpc/${var.vpc_id}"
subnet_arns = var.subnet_arns
segment_name = var.segment_name
tags = var.tags
}
data "aws_caller_identity" "current" {}
modules/cloudwan_vpc_attachment/outputs.tf:
output "attachment_id" {
value = aws_networkmanager_vpc_attachment.this.id
}
Module: cloudwan_policy
The policy is defined as a JSON document that you feed into aws_networkmanager_core_network_policy. You can use a template file (policy.json.tpl) to generate this JSON. This policy defines segments, routing rules, and attachments between them.
modules/cloudwan_policy/variables.tf:
variable "core_network_id" {
type = string
}
variable "policy_json" {
type = string
description = "Rendered policy JSON"
}
modules/cloudwan_policy/policy.json.tpl (Example skeleton, must be customized):
{
"Version": "2021-03-11",
"SegmentActions": {
"CreateSegment": [
{"Name": "NP_MEL_int_seg"},
{"Name": "NP_MEL_ext_seg"},
{"Name": "NP_MEL_ext_fw_seg"},
{"Name": "NP_MEL_prot_seg"},
{"Name": "NP_MEL_prot_fw_seg"},
{"Name": "NP_SYD_int_seg"},
{"Name": "NP_SYD_ext_seg"},
{"Name": "NP_SYD_ext_fw_seg"},
{"Name": "NP_SYD_prot_seg"},
{"Name": "NP_SYD_prot_fw_seg"},
{"Name": "segr_fw_seg"},
{"Name": "SDWAN_seg"},
{"Name": "PROD_MEL_int_seg"},
{"Name": "PROD_MEL_ext_seg"},
{"Name": "PROD_MEL_ext_fw_seg"},
{"Name": "PROD_MEL_prot_seg"},
{"Name": "PROD_MEL_prot_fw_seg"},
{"Name": "PROD_SYD_int_seg"},
{"Name": "PROD_SYD_ext_seg"},
{"Name": "PROD_SYD_ext_fw_seg"},
{"Name": "PROD_SYD_prot_seg"},
{"Name": "PROD_SYD_prot_fw_seg"},
{"Name": "Direct_Connect_seg"}
]
},
"SegmentRouting": {
"AllowRoutePropagation": [
{
"SegmentName": "NP_MEL_int_seg",
"AllowedRoutes": [
{"SegmentName": "NP_MEL_int_seg"},
{"SegmentName": "NP_MEL_prot_seg", "ThroughSegments": ["NP_MEL_prot_fw_seg"]},
{"SegmentName": "NP_MEL_ext_seg", "ThroughSegments": ["NP_MEL_ext_fw_seg"]},
...
/* You must fully define all route rules based on your requirements */
]
}
/* Additional segment-to-segment routing definitions go here */
]
}
}
modules/cloudwan_policy/main.tf:
resource "aws_networkmanager_core_network_policy" "this" {
core_network_id = var.core_network_id
policy_document = var.policy_json
}
output "policy_version_id" {
value = aws_networkmanager_core_network_policy.this.core_network_policy_version
}
You’d use a templatefile function in the calling code to render policy.json.tpl into var.policy_json.
Module: firewall
For firewall configuration, this could mean creating AWS Network Firewall or referencing a firewall appliance in a firewall VPC. For simplicity, assume you have a firewall appliance in a firewall VPC that’s already deployed. Here we just show how you might attach that firewall VPC to CloudWAN segments if needed.
modules/firewall/variables.tf:
variable "core_network_id" {
type = string
}
variable "vpc_id" {
type = string
}
variable "subnet_arns" {
type = list(string)
}
variable "segment_name" {
type = string
}
variable "tags" {
type = map(string)
default = {}
}
modules/firewall/main.tf:
module "firewall_attachment" {
source = "../cloudwan_vpc_attachment"
core_network_id = var.core_network_id
vpc_id = var.vpc_id
subnet_arns = var.subnet_arns
segment_name = var.segment_name
tags = var.tags
}
modules/firewall/outputs.tf:
output "firewall_attachment_id" {
value = module.firewall_attachment.attachment_id
}
Example Usage in nonprod/mel-vpc-attachment.tf
In your environment-specific files, you’ll call these modules and provide the appropriate variables:
variable "np_mel_int_vpc_id" {}
variable "np_mel_int_subnet_arns" {
type = list(string)
}
variable "core_network_id" {}
module "np_mel_int_vpc_attachment" {
source = "../modules/cloudwan_vpc_attachment"
core_network_id = var.core_network_id
vpc_id = var.np_mel_int_vpc_id
subnet_arns = var.np_mel_int_subnet_arns
segment_name = "NP_MEL_int_seg"
tags = {
Environment = "nonprod"
Region = "MEL"
Segment = "int"
}
}
You’d repeat similar code for each VPC attachment in MEL, SYD, etc., just changing variables and segment names accordingly.
Example Usage in nonprod/mel-cloudwan-policy.tf
You’ll need to provide the rendered policy JSON. One way is to use templatefile() in a calling file:
variable "core_network_id" {}
data "template_file" "policy_doc" {
template = file("../modules/cloudwan_policy/policy.json.tpl")
# If you have any variables in policy.json.tpl, pass them in vars = {}
}
module "np_mel_policy" {
source = "../modules/cloudwan_policy"
core_network_id = var.core_network_id
policy_json = data.template_file.policy_doc.rendered
}
Adjust segment names and route rules inside the policy.json.tpl file to fully reflect your routing requirements.
In Summary:
• Core Network Module: Creates the CloudWAN core network (if not existing yet).
• Segment Module: Mostly a placeholder because segments are defined in the policy.
• VPC Attachment Module: Attaches VPCs to segments.
• Policy Module: Manages the core network policy and defines the segments and routing rules.
• Firewall Module: Attaches firewall VPCs to the appropriate firewall segments.
You can now replicate this pattern for prod/ environment files, just changing variables and calling the same modules, ensuring proper isolation and routing as per your requirements.
Below is an example of a single Terraform configuration that directly creates the CloudWAN core network, defines segments (within the policy), creates VPC attachments, and applies a policy. This configuration does not use separate modules. Instead, all resources are defined at the top level. You will need to tailor this code to your environment (e.g., replace placeholder IDs, regions, CIDRs, VPCs, and segment names).
This is a minimal example to illustrate the approach:
File: main.tf
terraform {
required_version = ">= 1.3.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 4.0.0"
}
}
}
provider "aws" {
region = "ap-southeast-2"
}
#############################
# Variables (Adjust Values) #
#############################
# The global network ID is a prerequisite; this must already exist in your AWS environment.
variable "global_network_id" {
type = string
default = "GLOBAL-NETWORK-ID-HERE"
}
# Example VPC IDs (Replace with your actual VPC IDs)
variable "np_mel_int_vpc_id" {
type = string
default = "vpc-0examplemelint"
}
variable "np_mel_ext_vpc_id" {
type = string
default = "vpc-0examplemelext"
}
variable "np_mel_ext_fw_vpc_id" {
type = string
default = "vpc-0examplemelextfw"
}
variable "np_mel_prot_vpc_id" {
type = string
default = "vpc-0examplemelprot"
}
variable "np_mel_prot_fw_vpc_id" {
type = string
default = "vpc-0examplemelprotfw"
}
# Example Subnet ARNs for attachments (Replace with actual subnet ARNs)
# Typically, you attach 2-4 subnets for redundancy (one per AZ).
variable "np_mel_int_subnet_arns" {
type = list(string)
default = [
"arn:aws:ec2:ap-southeast-2:111111111111:subnet/subnet-0intA",
"arn:aws:ec2:ap-southeast-2:111111111111:subnet/subnet-0intB"
]
}
variable "np_mel_ext_subnet_arns" {
type = list(string)
default = [
"arn:aws:ec2:ap-southeast-2:111111111111:subnet/subnet-0extA",
"arn:aws:ec2:ap-southeast-2:111111111111:subnet/subnet-0extB"
]
}
# Similarly define variables for ext_fw, prot, and prot_fw VPC subnets:
variable "np_mel_ext_fw_subnet_arns" {
type = list(string)
default = [
"arn:aws:ec2:ap-southeast-2:111111111111:subnet/subnet-0extfwA",
"arn:aws:ec2:ap-southeast-2:111111111111:subnet/subnet-0extfwB"
]
}
variable "np_mel_prot_subnet_arns" {
type = list(string)
default = [
"arn:aws:ec2:ap-southeast-2:111111111111:subnet/subnet-0protA",
"arn:aws:ec2:ap-southeast-2:111111111111:subnet/subnet-0protB"
]
}
variable "np_mel_prot_fw_subnet_arns" {
type = list(string)
default = [
"arn:aws:ec2:ap-southeast-2:111111111111:subnet/subnet-0protfwA",
"arn:aws:ec2:ap-southeast-2:111111111111:subnet/subnet-0protfwB"
]
}
#############################
# Core Network Creation #
#############################
resource "aws_networkmanager_core_network" "core" {
global_network_id = var.global_network_id
description = "CloudWAN core network for multi-env routing"
tags = {
Name = "my-core-network"
}
}
output "core_network_id" {
value = aws_networkmanager_core_network.core.id
}
#############################
# Policy Definition #
#############################
# Create a local file for the policy JSON or inline heredoc.
# Here, we define segments and routing rules according to your design.
# Adjust segments and routing according to your requirements.
locals {
policy_document = <<-EOT
{
"Version": "2021-03-11",
"SegmentActions": {
"CreateSegment": [
{"Name": "NP_MEL_int_seg"},
{"Name": "NP_MEL_ext_seg"},
{"Name": "NP_MEL_ext_fw_seg"},
{"Name": "NP_MEL_prot_seg"},
{"Name": "NP_MEL_prot_fw_seg"}
/* Add other segments for SYD, PROD, etc. as needed */
]
},
"SegmentRouting": {
"AllowRoutePropagation": [
{
"SegmentName": "NP_MEL_int_seg",
"AllowedRoutes": [
{"SegmentName": "NP_MEL_int_seg"},
{
"SegmentName": "NP_MEL_ext_seg",
"ThroughSegments": ["NP_MEL_ext_fw_seg"]
},
{
"SegmentName": "NP_MEL_prot_seg",
"ThroughSegments": ["NP_MEL_prot_fw_seg"]
}
]
},
{
"SegmentName": "NP_MEL_ext_seg",
"AllowedRoutes": [
{"SegmentName": "NP_MEL_int_seg"},
{
"SegmentName": "NP_MEL_prot_seg",
"ThroughSegments": ["NP_MEL_prot_fw_seg"]
}
]
}
/* Add similar routing policies for other segments/environments/regional segments
and cross-environment rules (e.g., NP to PROD via ext and segr_fw) as needed */
]
}
}
EOT
}
resource "aws_networkmanager_core_network_policy" "policy" {
core_network_id = aws_networkmanager_core_network.core.id
policy_document = local.policy_document
}
output "policy_version" {
value = aws_networkmanager_core_network_policy.policy.core_network_policy_version
}
#############################
# VPC Attachments #
#############################
# Attach the NP MEL int VPC to NP_MEL_int_seg
resource "aws_networkmanager_vpc_attachment" "np_mel_int_attachment" {
core_network_id = aws_networkmanager_core_network.core.id
vpc_arn = "arn:aws:ec2:ap-southeast-2:${data.aws_caller_identity.current.account_id}:vpc/${var.np_mel_int_vpc_id}"
subnet_arns = var.np_mel_int_subnet_arns
segment_name = "NP_MEL_int_seg"
tags = {
Name = "np-mel-int-attachment"
}
}
# Attach the NP MEL ext VPC to NP_MEL_ext_seg
resource "aws_networkmanager_vpc_attachment" "np_mel_ext_attachment" {
core_network_id = aws_networkmanager_core_network.core.id
vpc_arn = "arn:aws:ec2:ap-southeast-2:${data.aws_caller_identity.current.account_id}:vpc/${var.np_mel_ext_vpc_id}"
subnet_arns = var.np_mel_ext_subnet_arns
segment_name = "NP_MEL_ext_seg"
tags = {
Name = "np-mel-ext-attachment"
}
}
# Attach the NP MEL ext fw VPC to NP_MEL_ext_fw_seg
resource "aws_networkmanager_vpc_attachment" "np_mel_ext_fw_attachment" {
core_network_id = aws_networkmanager_core_network.core.id
vpc_arn = "arn:aws:ec2:ap-southeast-2:${data.aws_caller_identity.current.account_id}:vpc/${var.np_mel_ext_fw_vpc_id}"
subnet_arns = var.np_mel_ext_fw_subnet_arns
segment_name = "NP_MEL_ext_fw_seg"
tags = {
Name = "np-mel-ext-fw-attachment"
}
}
# Attach the NP MEL prot VPC to NP_MEL_prot_seg
resource "aws_networkmanager_vpc_attachment" "np_mel_prot_attachment" {
core_network_id = aws_networkmanager_core_network.core.id
vpc_arn = "arn:aws:ec2:ap-southeast-2:${data.aws_caller_identity.current.account_id}:vpc/${var.np_mel_prot_vpc_id}"
subnet_arns = var.np_mel_prot_subnet_arns
segment_name = "NP_MEL_prot_seg"
tags = {
Name = "np-mel-prot-attachment"
}
}
# Attach the NP MEL prot fw VPC to NP_MEL_prot_fw_seg
resource "aws_networkmanager_vpc_attachment" "np_mel_prot_fw_attachment" {
core_network_id = aws_networkmanager_core_network.core.id
vpc_arn = "arn:aws:ec2:ap-southeast-2:${data.aws_caller_identity.current.account_id}:vpc/${var.np_mel_prot_fw_vpc_id}"
subnet_arns = var.np_mel_prot_fw_subnet_arns
segment_name = "NP_MEL_prot_fw_seg"
tags = {
Name = "np-mel-prot-fw-attachment"
}
}
data "aws_caller_identity" "current" {}
What This Code Does:
1. Creates a CloudWAN Core Network using aws_networkmanager_core_network.
2. Defines Segments and Routing Policies using aws_networkmanager_core_network_policy.
• The segments (NP_MEL_int_seg, NP_MEL_ext_seg, etc.) are created by the policy’s CreateSegment actions.
• The policy’s SegmentRouting section defines how routes propagate and what firewall segments to go through.
3. Attaches Existing VPCs to Specific Segments using aws_networkmanager_vpc_attachment. Each VPC attachment links the VPC to a specific segment.
4. Outputs the core network ID and policy version for reference.
Important:
• Update global_network_id with your actual global network ID.
• Update vpc_arn and subnet_arns variables with the correct values from your environment.
• Add more segments and VPC attachments as required for NP SYD, PROD MEL, PROD SYD, SDWAN segments, and Direct Connect.
• Expand the policy_document local variable’s JSON to cover all of your routing rules, including cross-environment routing via segr_fw_seg, ext_fw, prot_fw, etc.
• The rules given are simplified. In a real scenario, you must elaborate the policy JSON extensively to represent all your required inter-segment rules.
This single configuration file (with any necessary variable adjustments) will create and configure the CloudWAN resources without using modules.
Below is a comprehensive end-to-end example of how you might Resource Access Manager (RAM) share a CloudWAN core network from a prod account to a nonprod (NP) account. The example is organized into two folders—prod/ and np/—each containing minimal Terraform configurations. It illustrates:
1. Creating a CloudWAN core network in prod.
2. Creating a RAM resource share in prod.
3. Associating the nonprod account as a principal.
4. Sharing the CloudWAN core network with nonprod.
5. Referencing the shared CloudWAN in nonprod to create a VPC attachment.
Disclaimer: This is a simplified example for demonstration. You would adapt naming, variables, and references to suit your actual environment (e.g., separate files, modules, state management, encryption, etc.).
Folder Structure
cloudwan-project/
├── policy
│ └── core_network_policy.json # (Optional) Where you store the JSON policy
├── prod
│ ├── variables.tf
│ ├── prod_cloudwan.tf # Create CloudWAN & share via RAM
│ └── prod_ram_share.tf # Alternatively combined in one .tf file
├── np
│ ├── variables.tf
│ └── np_cloudwan.tf # Reference shared resource and attach to it
└── ...
Below, we’ll show the key .tf files in prod/ and np/.
prod/variables.tf
variable "region" {
type = string
default = "ap-southeast-2"
}
variable "nonprod_account_id" {
type = string
default = "222222222222" # Replace with your actual NP account ID
}
You might also define AWS provider configuration here, or in a separate providers.tf:
provider "aws" {
region = var.region
# credentials or profile for the prod account
}
prod/prod_cloudwan.tf
#######################
# 1. Create Core Network
#######################
resource "aws_networkmanager_core_network" "prod_core_network" {
name = "prod-core-network"
}
############################
# 2. Optionally Set a Policy
############################
resource "aws_networkmanager_core_network_policy" "prod_core_network_policy" {
core_network_id = aws_networkmanager_core_network.prod_core_network.id
# Option 1: inline JSON (example placeholder)
# policy_document = <<POLICY
# {
# "Segments": [ ... ],
# "SegmentActions": [ ... ],
# ...
# }
# POLICY
# Option 2: reference external file
policy_document = file("${path.module}/../policy/core_network_policy.json")
}
If you have no policy yet, you can skip creating the aws_networkmanager_core_network_policy resource. But typically, CloudWAN requires a policy to define segments and routing behavior.
prod/prod_ram_share.tf
############################################
# 3. Create a RAM Resource Share for CloudWAN
############################################
resource "aws_ram_resource_share" "prod_cloudwan_share" {
name = "prod-cloudwan-core-network-share"
allow_external_principals = false
}
#######################################################
# 4. Associate the Nonprod Account with This Share
#######################################################
resource "aws_ram_principal_association" "prod_cloudwan_share_np_account" {
resource_share_arn = aws_ram_resource_share.prod_cloudwan_share.arn
principal = var.nonprod_account_id
}
###################################################################
# 5. Associate the Core Network Resource with the RAM Resource Share
###################################################################
resource "aws_ram_resource_association" "prod_core_network_ram_assoc" {
resource_share_arn = aws_ram_resource_share.prod_cloudwan_share.arn
resource_arn = aws_networkmanager_core_network.prod_core_network.arn
}
This shares the CloudWAN core network with the nonprod account. The nonprod account can now “see” and attach to that shared resource, subject to any necessary IAM permissions and roles.
At This Point (in Prod Account)
• You have created a CloudWAN core network (aws_networkmanager_core_network.prod_core_network).
• You have optionally set a core network policy (segments, routing rules).
• You have created a RAM resource share, associated your nonprod account, and shared the core network.
Your prod account stands ready. Now, let’s see how nonprod uses it.
np/variables.tf
variable "region" {
type = string
default = "ap-southeast-2"
}
variable "prod_core_network_name" {
type = string
default = "prod-core-network" # Must match the name from the prod environment
}
You’d also define your AWS provider for nonprod here, pointing to the nonprod account:
provider "aws" {
region = var.region
# credentials or profile for the NP account
}
np/np_cloudwan.tf
Here’s how the nonprod side references the shared CloudWAN by name (or you could discover it via aws_ram data resources or pass in the ID/ARN from a pipeline).
##################################
# 1. Discover the Shared Core Network
##################################
data "aws_networkmanager_core_network" "prod_shared" {
// Provide a filter to find the name or ID that was shared
// name = var.prod_core_network_name
// OR a direct ID if you pass it as a variable
// depends on how you want to fetch the resource
name = var.prod_core_network_name
}
####################################################
# 2. Create a VPC Attachment to the Shared Core Network
####################################################
resource "aws_networkmanager_vpc_attachment" "np_mel_int" {
core_network_id = data.aws_networkmanager_core_network.prod_shared.core_network_id
vpc_arn = aws_vpc.my_np_mel_vpc.arn # Example
subnet_arns = [
aws_subnet.np_mel_subnet1.arn,
aws_subnet.np_mel_subnet2.arn
]
segment_name = "NP MEL int seg" # Must match a segment in the policy
tags = {
Environment = "nonprod"
Name = "NP-MEL-int-attachment"
}
}
• data "aws_networkmanager_core_network" "prod_shared" finds the resource that has been shared from prod.
• Then you attach your nonprod VPC to the CloudWAN via aws_networkmanager_vpc_attachment. Note that you specify:
• core_network_id from the data source.
• vpc_arn and subnet_arns from the nonprod VPC you want attached.
• segment_name that matches what is defined in the prod account’s core network policy.
You’d repeat as needed for all your nonprod VPC attachments: np_syd_int, np_mel_ext, np_mel_ext_fw, etc.
What Resources Need RAM Share?
• AWS Network Manager resources that you want a different AWS account to use or attach to. In this example:
• The CloudWAN core network is owned by prod, but must be accessible by nonprod.
• If you also want the nonprod account to see or attach to other cross-account resources (e.g., a shared Route 53 Resolver Rule, or a Transit Gateway—if you were using TGW in addition to or instead of CloudWAN), you’d share those resources as well via RAM.
• If nonprod has its own CloudWAN and you want prod to attach, you would do the reverse sharing from NP to prod.
Putting It All Together
1. Prod creates and owns the CloudWAN core network.
2. Prod sets up a RAM resource share to share the CloudWAN with nonprod.
3. Nonprod references that shared resource (either by using the data "aws_networkmanager_core_network" with the same name or by looking it up with a data resource for RAM shares).
4. Nonprod can then create VPC attachments pointing to the shared CloudWAN.
5. Both sides maintain appropriate IAM roles/permissions to ensure cross-account usage is allowed.
That’s the full example. In actual practice, you may:
• Break out attachments into separate .tf files per environment.
• Parameterize the references or resource ARNs.
• Use local modules or place the resources inline.
• Include additional resources like AWS Network Firewall.
But the above shows all the essential parts for RAM-sharing CloudWAN from a prod account to a nonprod account.
Below is an example of a single Terraform configuration that directly creates the CloudWAN core network, defines segments (within the policy), creates VPC attachments, and applies a policy. This configuration does not use separate modules. Instead, all resources are defined at the top level. You will need to tailor this code to your environment (e.g., replace placeholder IDs, regions, CIDRs, VPCs, and segment names).
This is a minimal example to illustrate the approach:
File: main.tf
terraform {
required_version = ">= 1.3.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 4.0.0"
}
}
}
provider "aws" {
region = "ap-southeast-2"
}
#############################
# Variables (Adjust Values) #
#############################
# The global network ID is a prerequisite; this must already exist in your AWS environment.
variable "global_network_id" {
type = string
default = "GLOBAL-NETWORK-ID-HERE"
}
# Example VPC IDs (Replace with your actual VPC IDs)
variable "np_mel_int_vpc_id" {
type = string
default = "vpc-0examplemelint"
}
variable "np_mel_ext_vpc_id" {
type = string
default = "vpc-0examplemelext"
}
variable "np_mel_ext_fw_vpc_id" {
type = string
default = "vpc-0examplemelextfw"
}
variable "np_mel_prot_vpc_id" {
type = string
default = "vpc-0examplemelprot"
}
variable "np_mel_prot_fw_vpc_id" {
type = string
default = "vpc-0examplemelprotfw"
}
# Example Subnet ARNs for attachments (Replace with actual subnet ARNs)
# Typically, you attach 2-4 subnets for redundancy (one per AZ).
variable "np_mel_int_subnet_arns" {
type = list(string)
default = [
"arn:aws:ec2:ap-southeast-2:111111111111:subnet/subnet-0intA",
"arn:aws:ec2:ap-southeast-2:111111111111:subnet/subnet-0intB"
]
}
variable "np_mel_ext_subnet_arns" {
type = list(string)
default = [
"arn:aws:ec2:ap-southeast-2:111111111111:subnet/subnet-0extA",
"arn:aws:ec2:ap-southeast-2:111111111111:subnet/subnet-0extB"
]
}
# Similarly define variables for ext_fw, prot, and prot_fw VPC subnets:
variable "np_mel_ext_fw_subnet_arns" {
type = list(string)
default = [
"arn:aws:ec2:ap-southeast-2:111111111111:subnet/subnet-0extfwA",
"arn:aws:ec2:ap-southeast-2:111111111111:subnet/subnet-0extfwB"
]
}
variable "np_mel_prot_subnet_arns" {
type = list(string)
default = [
"arn:aws:ec2:ap-southeast-2:111111111111:subnet/subnet-0protA",
"arn:aws:ec2:ap-southeast-2:111111111111:subnet/subnet-0protB"
]
}
variable "np_mel_prot_fw_subnet_arns" {
type = list(string)
default = [
"arn:aws:ec2:ap-southeast-2:111111111111:subnet/subnet-0protfwA",
"arn:aws:ec2:ap-southeast-2:111111111111:subnet/subnet-0protfwB"
]
}
#############################
# Core Network Creation #
#############################
resource "aws_networkmanager_core_network" "core" {
global_network_id = var.global_network_id
description = "CloudWAN core network for multi-env routing"
tags = {
Name = "my-core-network"
}
}
output "core_network_id" {
value = aws_networkmanager_core_network.core.id
}
#############################
# Policy Definition #
#############################
# Create a local file for the policy JSON or inline heredoc.
# Here, we define segments and routing rules according to your design.
# Adjust segments and routing according to your requirements.
locals {
policy_document = <<-EOT
{
"Version": "2021-03-11",
"SegmentActions": {
"CreateSegment": [
{"Name": "NP_MEL_int_seg"},
{"Name": "NP_MEL_ext_seg"},
{"Name": "NP_MEL_ext_fw_seg"},
{"Name": "NP_MEL_prot_seg"},
{"Name": "NP_MEL_prot_fw_seg"}
/* Add other segments for SYD, PROD, etc. as needed */
]
},
"SegmentRouting": {
"AllowRoutePropagation": [
{
"SegmentName": "NP_MEL_int_seg",
"AllowedRoutes": [
{"SegmentName": "NP_MEL_int_seg"},
{
"SegmentName": "NP_MEL_ext_seg",
"ThroughSegments": ["NP_MEL_ext_fw_seg"]
},
{
"SegmentName": "NP_MEL_prot_seg",
"ThroughSegments": ["NP_MEL_prot_fw_seg"]
}
]
},
{
"SegmentName": "NP_MEL_ext_seg",
"AllowedRoutes": [
{"SegmentName": "NP_MEL_int_seg"},
{
"SegmentName": "NP_MEL_prot_seg",
"ThroughSegments": ["NP_MEL_prot_fw_seg"]
}
]
}
/* Add similar routing policies for other segments/environments/regional segments
and cross-environment rules (e.g., NP to PROD via ext and segr_fw) as needed */
]
}
}
EOT
}
resource "aws_networkmanager_core_network_policy" "policy" {
core_network_id = aws_networkmanager_core_network.core.id
policy_document = local.policy_document
}
output "policy_version" {
value = aws_networkmanager_core_network_policy.policy.core_network_policy_version
}
#############################
# VPC Attachments #
#############################
# Attach the NP MEL int VPC to NP_MEL_int_seg
resource "aws_networkmanager_vpc_attachment" "np_mel_int_attachment" {
core_network_id = aws_networkmanager_core_network.core.id
vpc_arn = "arn:aws:ec2:ap-southeast-2:${data.aws_caller_identity.current.account_id}:vpc/${var.np_mel_int_vpc_id}"
subnet_arns = var.np_mel_int_subnet_arns
segment_name = "NP_MEL_int_seg"
tags = {
Name = "np-mel-int-attachment"
}
}
# Attach the NP MEL ext VPC to NP_MEL_ext_seg
resource "aws_networkmanager_vpc_attachment" "np_mel_ext_attachment" {
core_network_id = aws_networkmanager_core_network.core.id
vpc_arn = "arn:aws:ec2:ap-southeast-2:${data.aws_caller_identity.current.account_id}:vpc/${var.np_mel_ext_vpc_id}"
subnet_arns = var.np_mel_ext_subnet_arns
segment_name = "NP_MEL_ext_seg"
tags = {
Name = "np-mel-ext-attachment"
}
}
# Attach the NP MEL ext fw VPC to NP_MEL_ext_fw_seg
resource "aws_networkmanager_vpc_attachment" "np_mel_ext_fw_attachment" {
core_network_id = aws_networkmanager_core_network.core.id
vpc_arn = "arn:aws:ec2:ap-southeast-2:${data.aws_caller_identity.current.account_id}:vpc/${var.np_mel_ext_fw_vpc_id}"
subnet_arns = var.np_mel_ext_fw_subnet_arns
segment_name = "NP_MEL_ext_fw_seg"
tags = {
Name = "np-mel-ext-fw-attachment"
}
}
# Attach the NP MEL prot VPC to NP_MEL_prot_seg
resource "aws_networkmanager_vpc_attachment" "np_mel_prot_attachment" {
core_network_id = aws_networkmanager_core_network.core.id
vpc_arn = "arn:aws:ec2:ap-southeast-2:${data.aws_caller_identity.current.account_id}:vpc/${var.np_mel_prot_vpc_id}"
subnet_arns = var.np_mel_prot_subnet_arns
segment_name = "NP_MEL_prot_seg"
tags = {
Name = "np-mel-prot-attachment"
}
}
# Attach the NP MEL prot fw VPC to NP_MEL_prot_fw_seg
resource "aws_networkmanager_vpc_attachment" "np_mel_prot_fw_attachment" {
core_network_id = aws_networkmanager_core_network.core.id
vpc_arn = "arn:aws:ec2:ap-southeast-2:${data.aws_caller_identity.current.account_id}:vpc/${var.np_mel_prot_fw_vpc_id}"
subnet_arns = var.np_mel_prot_fw_subnet_arns
segment_name = "NP_MEL_prot_fw_seg"
tags = {
Name = "np-mel-prot-fw-attachment"
}
}
data "aws_caller_identity" "current" {}
What This Code Does:
1. Creates a CloudWAN Core Network using aws_networkmanager_core_network.
2. Defines Segments and Routing Policies using aws_networkmanager_core_network_policy.
• The segments (NP_MEL_int_seg, NP_MEL_ext_seg, etc.) are created by the policy’s CreateSegment actions.
• The policy’s SegmentRouting section defines how routes propagate and what firewall segments to go through.
3. Attaches Existing VPCs to Specific Segments using aws_networkmanager_vpc_attachment. Each VPC attachment links the VPC to a specific segment.
4. Outputs the core network ID and policy version for reference.
Important:
• Update global_network_id with your actual global network ID.
• Update vpc_arn and subnet_arns variables with the correct values from your environment.
• Add more segments and VPC attachments as required for NP SYD, PROD MEL, PROD SYD, SDWAN segments, and Direct Connect.
• Expand the policy_document local variable’s JSON to cover all of your routing rules, including cross-environment routing via segr_fw_seg, ext_fw, prot_fw, etc.
• The rules given are simplified. In a real scenario, you must elaborate the policy JSON extensively to represent all your required inter-segment rules.
This single configuration file (with any necessary variable adjustments) will create and configure the CloudWAN resources without using modules.
Below is an example Terraform configuration that demonstrates how to set up AWS Cloud WAN with multiple segments and insert a firewall VPC between traffic flows. This code includes:
• A global network and a core network.
• Three segments: segment-a, segment-fw, and segment-c.
• Three VPC attachments (for VPC A, VPC FW, and VPC C) associating each with its respective segment.
• A core network policy that ensures traffic from segment A to segment C passes through the firewall segment.
Important Notes:
1. Prerequisites:
• You must have already created three VPCs:
• VPC A (for example, vpc_a_id),
• VPC FW (the firewall VPC, vpc_fw_id),
• VPC C (vpc_c_id).
Each VPC should have at least one subnet. You will need the ARNs of these subnets (e.g., var.vpc_a_subnet_arns, etc.) for the attachment. Ensure your firewall VPC is set up with AWS Network Firewall or a suitable firewall appliance as required.
2. AWS Provider and Terraform Version:
Make sure you are using a recent AWS provider version (>= 5.x) and Terraform >= 1.x.
Some of the Cloud WAN features are relatively new, so ensure that your provider version supports aws_networkmanager_core_network_policy_version or the equivalent. If the resource doesn’t exist in your current provider, consider updating or using the AWS Cloud Control Provider (awscc_* resources).
3. Policy Document Schema:
The JSON policy used in aws_networkmanager_core_network_policy_version must follow the Cloud WAN policy schema. The example below is representative; you should review the latest AWS documentation to confirm the exact fields and structure:
AWS Cloud WAN Policy Reference
4. Placeholders:
Replace variable values (like var.vpc_a_id, var.vpc_fw_id, var.vpc_c_id, and subnet ARNs) with your actual values.
Example Terraform Code
terraform {
required_version = ">= 1.0.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
variable "vpc_a_id" {
type = string
}
variable "vpc_fw_id" {
type = string
}
variable "vpc_c_id" {
type = string
}
variable "vpc_a_subnet_arns" {
type = list(string)
}
variable "vpc_fw_subnet_arns" {
type = list(string)
}
variable "vpc_c_subnet_arns" {
type = list(string)
}
# 1. Create a Global Network
resource "aws_networkmanager_global_network" "this" {
description = "My Global Network"
}
# 2. Create a Core Network
resource "aws_networkmanager_core_network" "this" {
global_network_id = aws_networkmanager_global_network.this.id
description = "My Core Network"
# The initial core network is created without a custom policy.
# We'll create and attach a new policy version later.
}
# 3. Create VPC Attachments
resource "aws_networkmanager_vpc_attachment" "vpc_a_attach" {
core_network_id = aws_networkmanager_core_network.this.core_network_id
vpc_id = var.vpc_a_id
subnet_arns = var.vpc_a_subnet_arns
segment_name = "segment-a"
tags = {
Name = "vpc-a-attachment"
}
}
resource "aws_networkmanager_vpc_attachment" "vpc_fw_attach" {
core_network_id = aws_networkmanager_core_network.this.core_network_id
vpc_id = var.vpc_fw_id
subnet_arns = var.vpc_fw_subnet_arns
segment_name = "segment-fw"
tags = {
Name = "vpc-fw-attachment"
}
}
resource "aws_networkmanager_vpc_attachment" "vpc_c_attach" {
core_network_id = aws_networkmanager_core_network.this.core_network_id
vpc_id = var.vpc_c_id
subnet_arns = var.vpc_c_subnet_arns
segment_name = "segment-c"
tags = {
Name = "vpc-c-attachment"
}
}
# 4. Define the Core Network Policy
#
# This policy:
# - Defines three segments: segment-a, segment-fw, segment-c
# - Associates VPC attachments with their respective segments
# - Inserts a firewall between segment-a and segment-c traffic
#
# Make sure to verify that "INSERT_FIREWALL" action and policy structure
# align with the latest AWS documentation.
resource "aws_networkmanager_core_network_policy_version" "example" {
core_network_id = aws_networkmanager_core_network.this.core_network_id
policy_document = <<-EOT
{
"CoreNetworkConfiguration": {
"Segments": [
{ "Name": "segment-a" },
{ "Name": "segment-fw" },
{ "Name": "segment-c" }
],
"Edges": [],
"Policies": [
{
"PolicyType": "SEGMENT",
"SegmentActions": [
{
"Action": "INSERT_FIREWALL",
"FirewallSegment": "segment-fw",
"SourceSegments": ["segment-a"],
"DestinationSegments": ["segment-c"]
}
]
},
{
"PolicyType": "ATTACHMENT",
"Rules": [
{
"Action": "ASSOCIATE",
"SegmentName": "segment-a",
"ResourceTypes": ["VPC"]
},
{
"Action": "ASSOCIATE",
"SegmentName": "segment-fw",
"ResourceTypes": ["VPC"]
},
{
"Action": "ASSOCIATE",
"SegmentName": "segment-c",
"ResourceTypes": ["VPC"]
}
]
}
]
}
}
EOT
set_as_default = true
depends_on = [
aws_networkmanager_vpc_attachment.vpc_a_attach,
aws_networkmanager_vpc_attachment.vpc_fw_attach,
aws_networkmanager_vpc_attachment.vpc_c_attach
]
}
What This Configuration Does
• Global & Core Network: Sets up a global and core network to manage your WAN.
• Segments: The policy defines three segments:
• segment-a: Contains VPC A.
• segment-fw: Contains your firewall VPC.
• segment-c: Contains VPC C.
• Routing/Policy: The core network policy:
• Routes traffic from segment A to segment C via the firewall segment.
• Ensures each VPC attachment is associated with the correct segment.
• Firewall Insertion: The "INSERT_FIREWALL" action ensures that traffic going from A to C first passes through the firewall in segment-fw, allowing you to apply security inspections.
Additional Steps:
You must ensure that the firewall VPC is set up correctly with AWS Network Firewall or other suitable firewall solutions, and that the necessary endpoints or Transit Gateway Connect attachments are created as required. Those resources are not shown here (the user requested we exclude VPC definitions and firewall specifics).
This example provides a starting point. Always refer to the latest AWS and Terraform documentation to confirm resource attributes, policy schema, and any required dependencies.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment