Skip to content

Instantly share code, notes, and snippets.

@huynhbaoan
Created December 30, 2024 03:29
Show Gist options
  • Select an option

  • Save huynhbaoan/cf71c66e94086a49f138e861b1f1b059 to your computer and use it in GitHub Desktop.

Select an option

Save huynhbaoan/cf71c66e94086a49f138e861b1f1b059 to your computer and use it in GitHub Desktop.
Below is one cohesive example showing how to set up two Network Firewalls (one in NP MEL, one in NP SYD) and a CloudWAN policy that enforces traffic from the NP MEL prot segment to the NP SYD prot segment (and vice versa) to pass through both the NP MEL prot firewall and the NP SYD prot firewall.
Important Notes
1. We are not including VPC creations or VPC attachments—only the firewall resources and the CloudWAN policy references.
2. The code demonstrates a sample approach to modules and file structures. You can adapt naming and values to match your real environment.
3. The CloudWAN policy JSON is simplified but illustrates the essential concept of multiple firewalls in a strict path.
1. Directory Structure
Below is a proposed layout. You can adjust file names as needed, but this structure keeps things organized:
cloudwan-project/
np/
np_mel_syd_prot_firewalls.tf # top-level TF for creating both NP MEL and NP SYD "prot" firewalls
np_cloudwan_policy.tf # top-level TF to apply the CloudWAN policy
cloudwan_policy.json # the policy JSON describing segments & traffic rules
modules/
firewall/
main.tf
variables.tf
outputs.tf
cloudwan_policy/
main.tf
variables.tf
outputs.tf
2. Firewall Module (modules/firewall/)
This module will deploy an AWS Network Firewall (with a minimal rule group and policy) into an existing firewall VPC. You’ll call it twice—once for NP MEL prot firewall and once for NP SYD prot firewall.
modules/firewall/variables.tf
variable "name" {
type = string
description = "A name prefix or identifier for firewall resources."
}
variable "vpc_id" {
type = string
description = "ID of the VPC where the firewall is deployed."
}
variable "subnet_ids" {
type = list(string)
description = "Subnet IDs in which the firewall endpoints will be created."
}
variable "tags" {
type = map(string)
default = {}
description = "Tags for all firewall resources."
}
modules/firewall/main.tf
resource "aws_networkfirewall_rule_group" "stateful_group" {
capacity = 100
name = "${var.name}-stateful-rules"
type = "STATEFUL"
rule_group {
rules_source {
# Very simple ALLOWLIST example
rules_source_list {
generated_rules_type = "ALLOWLIST"
targets = ["0.0.0.0/0"] # ALLOW any domain/IP (placeholder)
target_types = ["TLS_SNI"]
}
}
}
tags = var.tags
}
resource "aws_networkfirewall_firewall_policy" "this" {
name = "${var.name}-policy"
firewall_policy {
stateless_default_actions = ["aws:forward_to_sfe"]
stateless_fragment_default_actions = ["aws:forward_to_sfe"]
stateful_engine_options {
rule_order = "STRICT_ORDER"
}
# Reference our single stateful rule group
stateful_rule_group_reference {
resource_arn = aws_networkfirewall_rule_group.stateful_group.arn
priority = 1
}
}
tags = var.tags
}
resource "aws_networkfirewall_firewall" "this" {
name = "${var.name}-firewall"
firewall_policy_arn = aws_networkfirewall_firewall_policy.this.arn
vpc_id = var.vpc_id
dynamic "subnet_mapping" {
for_each = var.subnet_ids
content {
subnet_id = subnet_mapping.value
}
}
# For demonstration, we turn off protection features
delete_protection = false
firewall_policy_change_protection = false
subnet_change_protection = false
description = "AWS Network Firewall for ${var.name}"
tags = var.tags
}
modules/firewall/outputs.tf
output "firewall_arn" {
description = "ARN of the AWS Network Firewall firewall"
value = aws_networkfirewall_firewall.this.arn
}
output "firewall_policy_arn" {
description = "ARN of the AWS Network Firewall policy"
value = aws_networkfirewall_firewall_policy.this.arn
}
output "firewall_name" {
description = "Name of the AWS Network Firewall firewall"
value = aws_networkfirewall_firewall.this.name
}
3. Create Two Firewalls (NP MEL & NP SYD)
In np/np_mel_syd_prot_firewalls.tf, we call the firewall module twice—once for NP MEL prot fw and once for NP SYD prot fw.
Note: We assume you already have VPCs and subnets for these firewall deployments. Replace the placeholder IDs with your real resource references.
############################################################
# NP MEL Protected Firewall
############################################################
module "np_mel_prot_fw" {
source = "../modules/firewall"
name = "np-mel-prot"
vpc_id = "vpc-0abcd1234melprot" # <--- Replace with real VPC ID
subnet_ids = [
"subnet-0aaa1234melA", # <--- Replace
"subnet-0bbb1234melB", # <--- Replace
]
tags = {
Environment = "nonprod"
Region = "mel"
Firewall = "prot"
}
}
############################################################
# NP SYD Protected Firewall
############################################################
module "np_syd_prot_fw" {
source = "../modules/firewall"
name = "np-syd-prot"
vpc_id = "vpc-0abcd1234sydprot" # <--- Replace with real VPC ID
subnet_ids = [
"subnet-0aaa1234sydA", # <--- Replace
"subnet-0bbb1234sydB", # <--- Replace
]
tags = {
Environment = "nonprod"
Region = "syd"
Firewall = "prot"
}
}
4. CloudWAN Policy Module (modules/cloudwan_policy/)
This module simply applies the JSON policy to an existing core network. You can keep your policy logic in a separate cloudwan_policy.json for clarity.
modules/cloudwan_policy/variables.tf
variable "core_network_id" {
type = string
description = "ID of the AWS Network Manager core network"
}
variable "policy_json_file" {
type = string
description = "Path to the JSON file that defines the CloudWAN policy"
}
variable "description" {
type = string
default = "CloudWAN policy update"
}
modules/cloudwan_policy/main.tf
resource "aws_networkmanager_core_network_policy" "this" {
core_network_id = var.core_network_id
policy_document = file(var.policy_json_file)
description = var.description
}
output "policy_version" {
description = "Policy version number"
value = aws_networkmanager_core_network_policy.this.core_network_policy_version
}
5. CloudWAN Policy JSON
In np/cloudwan_policy.json, we define segments and segmentActions such that NP MEL prot and NP SYD prot must always go through NP MEL prot fw and NP SYD prot fw, respectively. In a 2-region scenario, we effectively want:
1. MEL prot seg → SYD prot seg path:
• Must pass through np-mel-prot-fw-seg first
• Then through np-syd-prot-fw-seg next
2. SYD prot seg → MEL prot seg path:
• Must pass through np-syd-prot-fw-seg first
• Then np-mel-prot-fw-seg
A minimal example might look like this:
{
// 1) Define your segments
"segments": [
{ "name": "np-mel-prot-seg" },
{ "name": "np-mel-prot-fw-seg" },
{ "name": "np-syd-prot-seg" },
{ "name": "np-syd-prot-fw-seg" }
],
// 2) CloudWAN core config
"coreNetworkConfiguration": {
"edgeLocations": ["ALL_REGIONS"],
"asnRanges": ["64512-64516"]
},
// 3) The key: segmentActions
"segmentActions": [
// A) MEL prot -> SYD prot
{
"segmentName": "np-mel-prot-seg",
"destinations": [
{
"segmentName": "np-syd-prot-seg",
"mode": "STRICT",
// Must pass through MEL's firewall first
"attachmentName": "np-mel-prot-fw-seg"
}
]
},
{
// After MEL fw, must pass through SYD's fw to reach SYD prot
"segmentName": "np-mel-prot-fw-seg",
"destinations": [
{
"segmentName": "np-syd-prot-seg",
"mode": "STRICT",
"attachmentName": "np-syd-prot-fw-seg"
}
]
},
// B) SYD prot -> MEL prot (reverse path)
{
"segmentName": "np-syd-prot-seg",
"destinations": [
{
"segmentName": "np-mel-prot-seg",
"mode": "STRICT",
"attachmentName": "np-syd-prot-fw-seg"
}
]
},
{
"segmentName": "np-syd-prot-fw-seg",
"destinations": [
{
"segmentName": "np-mel-prot-seg",
"mode": "STRICT",
"attachmentName": "np-mel-prot-fw-seg"
}
]
}
]
}
Notice how we break the path into two steps for each direction so that traffic transits the local firewall segment, then the remote firewall segment, before reaching the remote prot segment.
6. Applying the Policy
In np/np_cloudwan_policy.tf, we reference the JSON file and the core network ID (assume it’s named aws_networkmanager_core_network.np_core_network.id or similar):
module "np_cloudwan_policy" {
source = "../modules/cloudwan_policy"
core_network_id = aws_networkmanager_core_network.np_core_network.id
policy_json_file = "${path.module}/cloudwan_policy.json"
description = "NP CloudWAN policy for MEL-SYD prot via firewall insertion"
}
This ensures:
1. The segments (np-mel-prot-seg, np-mel-prot-fw-seg, np-syd-prot-seg, np-syd-prot-fw-seg) exist in the core network.
2. Traffic from np-mel-prot-seg to np-syd-prot-seg forcibly goes:
• np-mel-prot-seg → np-mel-prot-fw-seg → np-syd-prot-fw-seg → np-syd-prot-seg
3. And the reverse path likewise.
7. High-Level Flow
Here’s what the final flow looks like after you attach your actual VPCs:
• NP MEL Protected VPC is attached to np-mel-prot-seg.
• NP MEL Protected FW VPC is attached to np-mel-prot-fw-seg.
• NP SYD Protected VPC is attached to np-syd-prot-seg.
• NP SYD Protected FW VPC is attached to np-syd-prot-fw-seg.
Now, traffic from NP MEL prot → NP SYD prot is:
1. Start in np-mel-prot-seg
2. Hit np-mel-prot-fw-seg (the local firewall)
3. Transit to np-syd-prot-fw-seg (the remote firewall)
4. Finally reach np-syd-prot-seg (the destination VPC)
And symmetrical in reverse.
8. Summary
• Firewall Module: Creates AWS Network Firewall resources (rule groups, firewall policy, firewall) inside a firewall VPC.
• CloudWAN Policy Module: Reads a JSON file defining segments, traffic rules, and service-insertion paths.
• Multiple Firewalls: Achieved by chaining “segmentActions” with "mode": "STRICT" so traffic must pass through local FW segment first, then the remote FW segment.
• 2 Directions: Simply replicate the rules in the JSON for both source→destination and destination→source.
Feel free to adapt the naming, subnets, and references to match your actual environment. Once your VPC attachments align with these segment names, the CloudWAN policy routes traffic as specified.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment