Skip to content

Module Banner

terraform-aws-arc-network

Module: sourcefuse/arc-network/aws

Registry: https://registry.terraform.io/modules/sourcefuse/arc-network/aws

Category: Networking / VPC

Source: https://github.com/sourcefuse/terraform-aws-arc-network

Latest Release Last Updated Terraform GitHub Actions

Quality gate

Overview

Creates a VPC with public/private subnets, NAT gateways (zonal or regional), internet gateway, route tables, and VPC endpoints.

What It Does

  • VPC with configurable CIDR block
  • Auto-generated or custom subnet maps
  • Zonal NAT gateways (one per AZ) or Regional NAT gateway (single multi-AZ)
  • Internet gateway and route tables
  • VPC endpoints for S3, DynamoDB, and other services
  • VPC Flow Logs to CloudWatch or S3
  • EKS-compatible subnet tagging
  • IPv6 support

For more information about this repository and its usage, please see Terraform AWS ARC Network Module Usage Guide.

arc_network_hla

Create the following resources in a single region.

  • VPC
  • Multi-AZ private and public subnets
  • Route tables, internet gateway, and NAT gateways (zonal or regional)
  • Configurable VPC Endpoints

Key Features

Regional NAT Gateway Support (Preview)

This module now supports AWS Regional NAT Gateway configuration, which provides: - Cost savings: Reduction in NAT Gateway costs (single resource vs one per AZ) - Built-in multi-AZ redundancy: Automatic failover across availability zones - Simplified management: One NAT Gateway resource instead of multiple - Auto and manual modes: Choose between AWS-managed or custom EIP allocation

Quickstart

module "network" {
  namespace   = var.namespace
  environment = var.environment

  name                    = "arc-poc"
  create_internet_geteway = true
  availability_zones      = ["us-east-1a", "us-east-1b", "us-east-1c"]
  cidr_block              = "10.0.0.0/16"
  vpc_endpoint_data = [
    {
      service            = "s3"
      route_table_filter = "private"
    },
    {
      service            = "dynamodb"
      route_table_filter = "private"
    }
  ]

  tags = module.tags.tags
}
module "network" {
  source                      = "sourcefuse/arc-network/aws"
  version                     = "3.0.0"

  namespace   = var.namespace
  environment = var.environment

  name                    = "arc-poc"
  create_internet_geteway = true
  subnet_map              = local.subnet_map
  cidr_block              = "10.0.0.0/16"
  vpc_endpoint_data = [
    {
      service            = "s3"
      route_table_filter = "private"
    },
    {
      service            = "dynamodb"
      route_table_filter = "private"
    }
  ]

  tags = module.tags.tags

}

locals {

  prefix = "arc-poc"

  subnet_map = {
    "${local.prefix}-public-az1" = {
      name                    = "${local.prefix}-public-az1"
      cidr_block              = "10.0.0.0/19"
      availability_zone       = "us-east-1a"
      nat_gateway_name        = "${local.prefix}-az1-ngtw01"
      attach_nat_gateway      = false
      create_nat_gateway      = true
      attach_internet_gateway = true
    },
    "${local.prefix}-public-az2" = {
      name                    = "${local.prefix}-public-az2"
      cidr_block              = "10.0.32.0/19"
      availability_zone       = "us-east-1b"
      nat_gateway_name        = "${local.prefix}-az2-ngtw01"
      attach_nat_gateway      = false
      create_nat_gateway      = true
      attach_internet_gateway = true
    },
    "${local.prefix}-db-az1" = {
      name                    = "${local.prefix}-db-az1"
      cidr_block              = "10.0.64.0/19"
      availability_zone       = "us-east-1a"
      nat_gateway_name        = "${local.prefix}-az1-ngtw01"
      attach_nat_gateway      = true
      create_nat_gateway      = false
      attach_internet_gateway = false
    },
    "${local.prefix}-db-az2" = {
      name                    = "${local.prefix}-db-az2"
      cidr_block              = "10.0.96.0/19"
      availability_zone       = "us-east-1b"
      nat_gateway_name        = "${local.prefix}-az2-ngtw01"
      attach_nat_gateway      = true
      create_nat_gateway      = false
      attach_internet_gateway = false
    },
    "${local.prefix}-app-az1" = {
      name                    = "${local.prefix}-app-az1"
      cidr_block              = "10.0.128.0/19"
      availability_zone       = "us-east-1a"
      nat_gateway_name        = "${local.prefix}-az1-ngtw01"
      attach_nat_gateway      = true
      create_nat_gateway      = false
      attach_internet_gateway = false
    },
    "${local.prefix}-app-az2" = {
      name                    = "${local.prefix}-app-az2"
      cidr_block              = "10.0.160.0/19"
      availability_zone       = "us-east-1b"
      nat_gateway_name        = "${local.prefix}-az2-ngtw01"
      attach_nat_gateway      = true
      create_nat_gateway      = false
      attach_internet_gateway = false
    }
  }
}

NAT Gateway

This module supports both traditional zonal NAT Gateways and the new Regional NAT Gateway.

Zonal NAT Gateway (Default)

Traditional approach with one NAT Gateway per availability zone:

1
2
3
4
5
6
7
8
9
module "network" {
  source = "sourcefuse/arc-network/aws"

  # ... other configuration

  nat_gateway_config = {
    mode = "zonal"  # This is the default
  }
}

Regional NAT Gateway

Single multi-AZ NAT Gateway with automatic redundancy:

Auto Mode (Recommended):

module "network" {
  source = "sourcefuse/arc-network/aws"

  # ... other configuration

  nat_gateway_config = {
    mode               = "regional"
    regional_auto_mode = true  # AWS manages AZs and EIPs
  }
}

Manual Mode (Custom EIP Control):

resource "aws_eip" "nat" {
  count  = 3
  domain = "vpc"
}

module "network" {
  source = "sourcefuse/arc-network/aws"

  # ... other configuration

  nat_gateway_config = {
    mode               = "regional"
    regional_auto_mode = false
    regional_az_eip_config = {
      "us-east-1a" = [aws_eip.nat[0].allocation_id]
      "us-east-1b" = [aws_eip.nat[1].allocation_id]
      "us-east-1c" = [aws_eip.nat[2].allocation_id]
    }
  }
}

EKS Compatibility

This module supports AWS EKS (Elastic Kubernetes Service) by enabling per-subnet custom tagging. EKS requires specific tags on subnets for proper ALB/NLB provisioning and cluster auto-discovery.

Required EKS Tags

  • Public subnets: kubernetes.io/role/elb = "1"
  • Private subnets: kubernetes.io/role/internal-elb = "1"
  • All subnets: kubernetes.io/cluster/<cluster-name> = "shared" or "owned"

Usage with Auto-Generated Subnets

Use additional_public_subnet_tags and additional_private_subnet_tags variables:

module "network" {
  # ... other configuration

  additional_public_subnet_tags = {
    "kubernetes.io/role/elb" = "1"
    "kubernetes.io/cluster/my-eks-cluster" = "shared"
  }

  additional_private_subnet_tags = {
    "kubernetes.io/role/internal-elb" = "1"
    "kubernetes.io/cluster/my-eks-cluster" = "shared"
  }
}

Usage with Custom Subnets

Add tags field to each subnet in subnet_map:

1
2
3
4
5
6
7
8
9
subnet_map = {
  "public-subnet" = {
    # ... subnet configuration
    tags = {
      "kubernetes.io/role/elb" = "1"
      "kubernetes.io/cluster/my-eks-cluster" = "shared"
    }
  }
}

Required Inputs

Name Type Description
namespace string Namespace prefix
environment string Deployment environment
name string VPC name
cidr_block string VPC CIDR block
## Key Outputs
Name Description
id VPC ID
private_subnet_ids Private subnet IDs
public_subnet_ids Public subnet IDs
nat_gateway_ids NAT gateway IDs
## Full Variable & Output Reference

The complete inputs/outputs reference is auto-generated below.

Requirements

Name Version
terraform >= 1.3, < 2.0.0
aws >= 5.0, < 7.0

Providers

Name Version
aws 6.35.1

Modules

Name Source Version
kms sourcefuse/arc-kms/aws 1.0.11

Resources

Name Type
aws_cloudwatch_log_group.this resource
aws_eip.nat_gw resource
aws_flow_log.this resource
aws_iam_policy.this resource
aws_iam_role.this resource
aws_iam_role_policy_attachment.attach_flow_logs_policy resource
aws_internet_gateway.this resource
aws_nat_gateway.regional resource
aws_nat_gateway.this resource
aws_route.additional resource
aws_route.internet_gw resource
aws_route.nat resource
aws_route.nat_regional resource
aws_route_table.this resource
aws_route_table_association.additional resource
aws_route_table_association.this resource
aws_subnet.this resource
aws_vpc.this resource
aws_vpc_dhcp_options.this resource
aws_vpc_dhcp_options_association.this resource
aws_vpc_endpoint.this resource
aws_caller_identity.current data source
aws_iam_policy_document.assume data source
aws_iam_policy_document.flow_logs_policy data source
aws_region.current data source
aws_region.this data source
aws_route_tables.private data source
aws_route_tables.public data source

Inputs

Name Description Type Default Required
additional_private_subnet_tags (optional) Additional tags for auto-generated private subnets map(string) {} no
additional_public_subnet_tags (optional) Additional tags for auto-generated public subnets map(string) {} no
assign_generated_ipv6_cidr_block Requests an Amazon-provided IPv6 CIDR block with a /56 prefix length for the VPC. bool false no
availability_zones (optional) List of availability zones , if subnet map is null , subnet map automatically derived list(string) [] no
cidr_block The CIDR block for the VPC. string n/a yes
create_internet_gateway (optional) Whether to create internet gateway bool true no
dhcp_options_config Configuration for VPC DHCP options. Set to null to use default AWS DHCP options.
object({
domain_name = optional(string)
domain_name_servers = optional(list(string))
ipv6_address_preferred_lease_time = optional(number)
ntp_servers = optional(list(string))
netbios_name_servers = optional(list(string))
netbios_node_type = optional(number)
tags = optional(map(string), {})
})
null no
enable_dns_hostnames A boolean flag to enable/disable DNS hostnames in the VPC. bool true no
enable_dns_support A boolean flag to enable/disable DNS support in the VPC. bool true no
enable_network_address_usage_metrics Enable or disable network address usage metrics. bool false no
environment Specifies the name of the deployment environment (e.g., dev, stage, prod). string n/a yes
instance_tenancy A tenancy option for instances launched into the VPC. Can be 'default' or 'dedicated'. string "default" no
internet_gateway_name (optional) If the Internet Gateway name is not provided, it will be automatically derived. string null no
ipv4_ipam_pool_id The IPv4 IPAM pool ID from which to allocate the CIDR. string null no
ipv4_netmask_length The netmask length of the IPv4 CIDR block to allocate to the VPC. number null no
ipv6_cidr_block The IPv6 CIDR block to associate with your VPC. string null no
ipv6_cidr_block_network_border_group The network border group of the IPv6 CIDR block. string null no
ipv6_ipam_pool_id The IPv6 IPAM pool ID from which to allocate the CIDR. string null no
ipv6_netmask_length The netmask length of the IPv6 CIDR block to allocate to the VPC. number null no
kms_config n/a
object({
deletion_window_in_days = number
enable_key_rotation = bool
})
{
"deletion_window_in_days": 30,
"enable_key_rotation": true
}
no
name VPC name string n/a yes
namespace Namespace name string n/a yes
nat_gateway_config NAT Gateway configuration. Supports both zonal (traditional) and regional (multi-AZ) NAT Gateways.

- mode: 'zonal' (default) creates one NAT Gateway per AZ, 'regional' creates a single multi-AZ NAT Gateway
- regional_auto_mode: When mode is 'regional', set to true for auto mode (AWS manages AZs/EIPs) or false for manual mode
- regional_az_eip_config: Required when mode is 'regional' and regional_auto_mode is false. Map of AZ to list of EIP allocation IDs
object({
mode = optional(string, "zonal") # "zonal" or "regional"
regional_auto_mode = optional(bool, true)
regional_az_eip_config = optional(map(list(string)), {}) # { "us-east-1a" = ["eipalloc-xxx"], "us-east-1b" = ["eipalloc-yyy"] }
})
{
"mode": "zonal",
"regional_auto_mode": true,
"regional_az_eip_config": {}
}
no
subnet_map A map defining the configuration of subnets, their attributes, and associated resources.
Each subnet configuration can include the following details:

- name: Name of the subnet.
- cidr_block: CIDR block for the subnet.
- availability_zone: The availability zone where the subnet is located.
- enable_resource_name_dns_a_record_on_launch: Enable or disable DNS A records for EC2 instances launched in this subnet (default: false).
- enable_resource_name_dns_aaaa_record_on_launch: Enable or disable DNS AAAA records for EC2 instances launched in this subnet (default: false).
- map_public_ip_on_launch: Specify whether to auto-assign a public IP for instances in this subnet (default: false).
- ipv6_native: Enable or disable native IPv6 support for the subnet (default: false).
- assign_ipv6_address_on_creation: Whether to automatically assign an IPv6 address to instances launched in the subnet (default: false).
- ipv6_cidr_block: The IPv6 CIDR block associated with the subnet (optional).
- enable_dns64: Enable or disable DNS64 in the subnet (default: false).
- nat_gateway_name: Name of the NAT Gateway attached to the subnet (optional).
- create_nat_gateway: Specify whether to create a NAT Gateway for the subnet (default: true).
- attach_nat_gateway: Specify whether to attach an existing NAT Gateway to the subnet (default: false).
- attach_internet_gateway: Specify whether to attach an Internet Gateway to the subnet (default: false).
- additional_routes: List of additional routes to be added to the subnet route table, typically to route traffic to other services like Transit Gateway. Each route includes:
- type: Type of resource (default: "transit-gateway").
- id: The ID of the route target (e.g., a Transit Gateway ID).
- cidr_block: The destination CIDR block for the route.
- destination_ipv6_cidr_block: The destination IPV6 CIDR block for the route.
- tags: Additional tags to apply to the subnet (default: {}).
map(object({
name = string
cidr_block = string
availability_zone = string
enable_resource_name_dns_a_record_on_launch = optional(bool, false)
enable_resource_name_dns_aaaa_record_on_launch = optional(bool, false)
map_public_ip_on_launch = optional(bool, false)
ipv6_native = optional(bool, false)
assign_ipv6_address_on_creation = optional(bool, false)
ipv6_cidr_block = optional(string, null)
enable_dns64 = optional(bool, false)
nat_gateway_name = optional(string, null)
create_nat_gateway = optional(bool, true)
attach_nat_gateway = optional(bool, false)
attach_internet_gateway = optional(bool, false)
additional_routes = optional(list(object({
type = optional(string, "transit-gateway") // possible values : network-interface ,transit-gateway, vpc-endpoint, vpc-peering-connection
id = string
destination_cidr_block = optional(string, null)
destination_ipv6_cidr_block = optional(string, null)
}
)), [])
tags = optional(map(string), {})
}))
null no
tags (optional) Tags for VPC resources map(string) {} no
vpc_endpoint_data (optional) List of VPC endpoints to be created
list(object({
service = string
route_table_filter = optional(string, "private") // possible values 'private' and 'public'
policy_doc = optional(string, null)
private_dns_enabled = optional(bool, false)
security_group_ids = optional(list(string), [])
}))
[] no
vpc_flow_log_config If s3_bucket_arn is null, only CloudWatch logging is enabled by default. If s3_bucket_arn is provided, S3 logging is enabled.
object({
enable = bool
retention_in_days = number
s3_bucket_arn = string
traffic_type = optional(string, "ALL")
})
{
"enable": true,
"retention_in_days": 7,
"s3_bucket_arn": null,
"traffic_type": "ALL"
}
no

Outputs

Name Description
default_route_table_id The Default Route Table ID for the VPC
dhcp_options_arn The ARN of the DHCP Options Set
dhcp_options_id The ID of the DHCP Options Set
id The VPC ID
igw_id Internet gateway ID for the VPC
main_route_table_id The Main Route Table ID for the VPC
nat_gateway_ids NAT Gateway IDs (zonal mode)
private_subnet_ids Private subnet IDs
public_subnet_ids Public subnet IDs
regional_nat_gateway_addresses Regional NAT Gateway addresses per AZ
regional_nat_gateway_id Regional NAT Gateway ID (regional mode)
vpc_cidr The VPC CIDR block
vpc_default_network_acl_id The ID of the network ACL created by default on VPC creation
vpc_endpoint_arn The ARN of the VPC Endpoint Connection.

Development

Prerequisites

Configurations

  • Configure pre-commit hooks
    pre-commit install
    
  • Configure golang deps for tests
    go get github.com/gruntwork-io/terratest/modules/terraform
    go get github.com/stretchr/testify/assert
    

Git commits

while Contributing or doing git commit please specify the breaking change in your commit message whether its major,minor or patch

For Example

git commit -m "your commit message #major"
By specifying this , it will bump the version and if you dont specify this in your commit message then by default it will consider patch and will bump that accordingly

Tests

  • Tests are available in test directory
  • In the test directory, run the below command
    go test -timeout 1800s
    

Contributing

See CONTRIBUTING.md for commit conventions and development setup.

Authors

This project is authored by: - SourceFuse