Skip to main content

NTC Core Network

Release Notes Source Code Implementation Blueprint

Description​

NTC Core Network simplifies the management of your AWS core networking infrastructure, including Transit Gateway, VPN, and Direct Connect. This building block automates the setup of secure and scalable connectivity across AWS accounts and on-premises environments, supporting both single-region and multi-region network deployments.

With NTC Core Network, you can streamline hybrid network configurations, enforce consistent routing policies, and ensure reliable, high-performance connections. Designed for flexibility, this module provides a robust foundation for your AWS and hybrid network architecture.

Usage​

Latest Release1.2.1
# --------------------------------------------------------------------------------------------------
# Β¦ NTC CORE NETWORK
# --------------------------------------------------------------------------------------------------
module "ntc_core_network_frankfurt" {
source = "github.com/nuvibit-terraform-collection/terraform-aws-ntc-core-network?ref=X.X.X"

# ------------------------------------------------------------------------------------------------
# Β¦ TRANSIT GATEWAY
# ------------------------------------------------------------------------------------------------
transit_gateway = {
name = "tgw-core-frankfurt"
description = "core network in frankfurt"
amazon_side_asn = 64512
default_route_table_association = false
default_route_table_propagation = false
dns_support = true
multicast_support = false
vpn_ecmp_support = true
security_group_referencing_support = true
cidr_blocks = []
route_table_names = [
"tgw-core-rtb-hub",
"tgw-core-rtb-spoke-prod",
"tgw-core-rtb-spoke-dev",
"tgw-core-rtb-spoke-int",
"tgw-core-rtb-onprem",
]
# (optional) share subnet with Organizations, OUs or Accounts - requires RAM to be enabled for Organizations
auto_accept_shared_attachments = true
ram_share_principals = [
local.ntc_parameters["mgmt-organizations"]["ou_ids"]["/root/workloads"]
]
ram_share_allow_external_principals = false
}

# transit gateway flow logs can be delivered to s3, cloudwatch and kinesis-data-firehose.
# it is possible to send flow logs from a single transit gateway to multiple targets in parallel e.g. s3 + cloudwatch
transit_gateway_flow_log_destinations = [
{
destination_type = "s3"
destination_arn = local.ntc_parameters["log-archive"]["log_bucket_arns"]["transit_gateway_flow_logs"]
# decide wether to capture ALL, only ACCEPT or only REJECT traffic
traffic_type = "ALL"
# interval must be 60 seconds (1min)
max_aggregation_interval = 60
# log format fields can be customized
# https://docs.aws.amazon.com/vpc/latest/userguide/flow-logs.html#flow-logs-default
# log_format = "$${account-id} $${action} $${bytes} $${dstaddr} $${dstport} $${end} $${instance-id} $${interface-id} $${log-status} $${packets} $${pkt-dstaddr} $${pkt-srcaddr} $${protocol} $${srcaddr} $${srcport} $${start} $${subnet-id} $${tcp-flags} $${type} $${version} $${vpc-id}"
},
# {
# destination_type = "cloud-watch-logs"
# # cloudwatch log group will be created if 'destination_arn' is omitted
# destination_arn = ""
# cloudwatch_options = {
# use_existing_kms_key = false
# kms_key_arn = ""
# # iam role is required when an existing log group is defined in 'destination_arn'
# iam_role_arn = ""
# }
# },
# {
# destination_type = "kinesis-data-firehose"
# destination_arn = "KINESIS_DATA_FIREHOSE_ARN"
# }
]

# ------------------------------------------------------------------------------------------------
# Β¦ (OPTIONAL) DIRECT CONNECT
# ------------------------------------------------------------------------------------------------
direct_connect = {
# direct connect gateway is a globally available resource to connect to the VPCs or VPNs that are attached to a transit gateway
# you can connect up to 6 transit gateways in one or more regions with a single direct connect gateway
dx_gateways = [
{
name = "dx-gateway"
amazon_side_asn = 65500
}
]
# associate direct connect gateway with transit gateway defined in 'transit_gateway'
transit_gateway_associations = [
{
# either reference the direct connect gateway defined in 'direct_connect.dx_gateways'
dx_gateway_name = "dx-gateway"
# or reference the id of an existing direct connect gateway
dx_gateway_id = ""
# reference transit gateway route table defined in 'transit_gateway'
transit_gateway_association_with_route_table_name = "tgw-core-rtb-onprem"
transit_gateway_propagation_to_route_table_names = [
"tgw-core-rtb-hub",
"tgw-core-rtb-spoke-prod",
"tgw-core-rtb-spoke-dev",
"tgw-core-rtb-spoke-int",
]
# only the allowed prefixes entered will be advertised to on-premises and cannot be overlapping across transit gateways
allowed_prefixes = ["10.100.10.0/24", "10.100.20.0/24", "10.100.30.0/24"]
}
]
# dedicated network connections between on-premises and aws direct connect locations
dx_dedicated_connections = [
{
name = "dx-con-frankfurt"
# bandwidth can be one of 1, 2, 3, 4, 10, 20, 30, 40, 100, 200, 300, 400 Gpbs
# upgrading bandwidth without downtime in ranges 1-4, 10-40 or 100-400
# upgrading bandwidth from 1 Gpbs to 10 Gpbs will recreate connections
#Β WARNING: recreating connections will cause downtime if no failover is availble (e.g. secondary direct connect or vpn)
bandwidth_in_gpbs = 1
# associated region of direct connect location must match with provider region
# https://aws.amazon.com/directconnect/locations/
location_name = "Equinix FR5, Frankfurt, DEU"
provider_name = "Equinix, Inc."
macsec_support = false
# avoid deleting connection when destroyed and instead remove from the Terraform state
skip_destroy = false
# private virtual interfaces can be used to access a VPC using private IP addresses
# public virtual interfaces can access all aws public services using public IP addresses
# transit virtual interfaces should be used to access one or more transit gateways associated with direct connect gateways (recommended)
virtual_interfaces = [
{
name = "dx-vif-transit-frankfurt"
type = "transit"
# either reference the direct connect gateway defined in 'direct_connect.dx_gateways'
dx_gateway_name = "dx-gateway"
# or reference the id of an existing direct connect gateway
dx_gateway_id = ""
vlan = 100
address_family = "ipv4"
customer_side_asn = 65352
bgp_auth_key = null
mtu = 1500
sitelink_enabled = false
# the destination IPv4 CIDR address to which AWS should send traffic (default is a /29 from 169.254.0.0/16)
customer_peer_ip = "10.0.0.1/30"
# the IPv4 CIDR address to use to send traffic to AWS (default is a /29 from 169.254.0.0/16)
amazon_peer_ip = "10.0.0.2/30"
}
]
}
]
}

# ------------------------------------------------------------------------------------------------
# Β¦ (OPTIONAL) S2S VPN
# ------------------------------------------------------------------------------------------------
virtual_private_network = {
# a customer gateway device is a physical or software appliance that you own or manage in your on-premises network
customer_gateways = [
{
name = "i7_zrh"
device_name = "i7zrhr1"
customer_side_asn = 65000
ip_address = "1.2.3.4"
certificate_arn = null
}
]
# VPN connections will be automatically attached to core network transit gateway defined in 'transit_gateway'
# a VPN connection offers two VPN tunnels between a virtual private gateway or transit gateway on the AWS side, and a customer gateway on the on-premises side
# maximum bandwidth per VPN tunnel is 1.25 Gbps but you can add additional vpn connections to increase bandwith when ECMP is enabled on transit gateway
vpn_connections = [
{
name = "i7_zrh_vpn1"
# reference customer gateway defined in 'customer_gateways'
customer_gateway_name = "i7_zrh"
# reference transit gateway route table defined in 'transit_gateway'
transit_gateway_association_with_route_table_name = "tgw-core-rtb-onprem"
transit_gateway_propagation_to_route_table_names = [
"tgw-core-rtb-hub",
"tgw-core-rtb-spoke-prod",
"tgw-core-rtb-spoke-dev",
"tgw-core-rtb-spoke-int",
]
# by default dynamic routing with bgp is enabled
# static routes need to be added to transit gateway route table
static_routes_only = false
enable_acceleration = false
address_family = "ipv4"
local_network_cidr = "0.0.0.0/0"
remote_network_cidr = "0.0.0.0/0"
outside_ip_address_type = "PublicIpv4"
# attachment_id required when 'outside_ip_address_type' is 'PrivateIpv4'
transport_transit_gateway_attachment_id = ""
# (optional) ipsec tunnel1 configuration
tunnel1_options = {
inside_cidr = null
preshared_key = null
dpd_timeout_action = "clear"
dpd_timeout_seconds = 30
enable_tunnel_lifecycle_control = false
ike_versions = ["ikev1", "ikev2"]
phase1_dh_group_numbers = [2, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]
phase1_encryption_algorithms = ["AES128", "AES256", "AES128-GCM-16", "AES256-GCM-16"]
phase1_integrity_algorithms = ["SHA1", "SHA2-256", "SHA2-384", "SHA2-512"]
phase1_lifetime_seconds = 28800
phase2_dh_group_numbers = [2, 5, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]
phase2_encryption_algorithms = ["AES128", "AES256", "AES128-GCM-16", "AES256-GCM-16"]
phase2_integrity_algorithms = ["SHA1", "SHA2-256", "SHA2-384", "SHA2-512"]
phase2_lifetime_seconds = 3600
rekey_fuzz_percentage = 100
rekey_margin_time_seconds = 540
replay_window_size = 1024
startup_action = "add"
cloudwatch_log_options = {
enabled = false
log_group_arn = ""
log_output_format = "json"
}
}
# (optional) ipsec tunnel2 configuration
tunnel2_options = {
inside_cidr = null
preshared_key = null
dpd_timeout_action = "clear"
dpd_timeout_seconds = 30
enable_tunnel_lifecycle_control = false
ike_versions = ["ikev1", "ikev2"]
phase1_dh_group_numbers = [2, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]
phase1_encryption_algorithms = ["AES128", "AES256", "AES128-GCM-16", "AES256-GCM-16"]
phase1_integrity_algorithms = ["SHA1", "SHA2-256", "SHA2-384", "SHA2-512"]
phase1_lifetime_seconds = 28800
phase2_dh_group_numbers = [2, 5, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]
phase2_encryption_algorithms = ["AES128", "AES256", "AES128-GCM-16", "AES256-GCM-16"]
phase2_integrity_algorithms = ["SHA1", "SHA2-256", "SHA2-384", "SHA2-512"]
phase2_lifetime_seconds = 3600
rekey_fuzz_percentage = 100
rekey_margin_time_seconds = 540
replay_window_size = 1024
startup_action = "add"
cloudwatch_log_options = {
enabled = false
log_group_arn = ""
log_output_format = "json"
}
}
}
]
}

providers = {
aws = aws.euc1
}
}

Requirements​

The following requirements are needed by this module:

  • terraform (>= 1.3.0)

  • aws (>= 5.69.0)

  • time (>= 0.11)

Providers​

The following providers are used by this module:

  • aws (>= 5.69.0)

  • time (>= 0.11)

Modules​

The following Modules are called:

flow_logs​

Source: ./modules/flow-logs

Version:

Resources​

The following resources are used by this module:

Required Inputs​

No required inputs.

Optional Inputs​

The following input variables are optional (have default values):

customer_managed_prefix_lists​

Description: Define customer managed prefix lists to be referenced in route tables.

Type:

list(object({
name = optional(string, null)
address_family = optional(string, "IPv4")
entries = optional(list(object({
cidr = string
description = optional(string, null)
})), [])
max_entries = optional(number, null)
ram_share_principals = optional(list(string), [])
ram_share_allow_external_principals = optional(bool, false)
}))

Default: []

direct_connect​

Description: Configuration of core network direct connect.

Type:

object({
dx_gateways = optional(list(object({
name = string
amazon_side_asn = optional(number, 64513)
})), [])
transit_gateway_associations = optional(list(object({
dx_gateway_name = string
dx_gateway_id = optional(string, null)
allowed_prefixes = optional(list(string), [])
transit_gateway_association_with_route_table_name = optional(string, "")
transit_gateway_propagation_to_route_table_names = optional(list(string), [])
})), [])
dx_dedicated_connections = optional(list(object({
name = string
bandwidth_in_gpbs = number
location_name = string
provider_name = string
macsec_support = optional(bool, false)
encryption_mode = optional(string, null)
skip_destroy = optional(bool, true)
virtual_interfaces = optional(list(object(
{
name = string
vlan = number
type = optional(string, "transit")
dx_gateway_name = optional(string, "")
dx_gateway_id = optional(string, null)
address_family = optional(string, "ipv4")
customer_side_asn = optional(number, 65352)
bgp_auth_key = optional(string, null)
mtu = optional(number, 1500)
sitelink_enabled = optional(bool, false)
customer_peer_ip = optional(string, "10.0.0.1/30")
amazon_peer_ip = optional(string, "10.0.0.2/30")
}
)), [])
})), [])
})

Default: {}

transit_gateway​

Description: Configuration of core network transit gateway.

Type:

object({
create_transit_gateway = optional(bool, true)
name = optional(string, "tgw-core")
description = optional(string, "core network")
amazon_side_asn = optional(number, 64512)
default_route_table_association = optional(bool, false)
default_route_table_propagation = optional(bool, false)
dns_support = optional(bool, true)
multicast_support = optional(bool, false)
vpn_ecmp_support = optional(bool, true)
security_group_referencing_support = optional(bool, false)
cidr_blocks = optional(list(string), [])
route_table_names = optional(list(string), ["tgw-route-table-hub", "tgw-route-table-spoke"])
cross_account_vpc_attachment_ids = optional(list(string), [])
auto_accept_shared_attachments = optional(bool, false)
ram_share_principals = optional(list(string), [])
ram_share_allow_external_principals = optional(bool, false)
})

Default: {}

transit_gateway_flow_log_destinations​

Description: List of transit gateway flow log destinations. transit gateway flow logs can be delivered to S3, CloudWatch or Kineses Data Firehose and multiple destinations can be configured in parallel.

Type:

list(object({
destination_type = string
destination_arn = optional(string, "")
traffic_type = optional(string, "ALL")
log_format = optional(string, null)
max_aggregation_interval = optional(number, 60)
s3_options = optional(object({
file_format = optional(string, "plain-text")
hive_compatible_partitions = optional(bool, false)
per_hour_partition = optional(bool, false)
}), {})
cloudwatch_options = optional(object({
iam_role_arn = optional(string, "")
iam_role_prefix = optional(string, "transit-gateway-flow-logs-role-")
iam_policy_prefix = optional(string, "transit-gateway-flow-logs-to-cloudwatch-")
use_existing_kms_key = optional(bool, false)
kms_key_arn = optional(string, "")
permissions_boundary_arn = optional(string, null)
name_prefix = optional(string, "/aws/transit-gateway-flow-logs/")
retention_in_days = optional(number, null)
}), {})
}))

Default: []

virtual_private_network​

Description: Configuration of core network site-2-site vpn.

Type:

object({
customer_gateways = optional(list(object({
name = string
device_name = optional(string, null)
ip_address = string
customer_side_asn = optional(number, 65000)
certificate_arn = optional(string, "")
})), [])
vpn_connections = optional(list(object({
name = string
customer_gateway_name = string
transit_gateway_association_with_route_table_name = optional(string, "")
transit_gateway_propagation_to_route_table_names = optional(list(string), [])
static_routes_only = optional(string, false)
enable_acceleration = optional(string, false)
address_family = optional(string, "ipv4")
local_network_cidr = optional(string, "0.0.0.0/0")
remote_network_cidr = optional(string, "0.0.0.0/0")
outside_ip_address_type = optional(string, "PublicIpv4")
transport_transit_gateway_attachment_id = optional(string, "")
tunnel1_options = optional(object({
inside_cidr = optional(string, null)
preshared_key = optional(string, null)
dpd_timeout_action = optional(string, "clear")
dpd_timeout_seconds = optional(number, 30)
enable_tunnel_lifecycle_control = optional(bool, false)
ike_versions = optional(list(string), ["ikev1", "ikev2"])
phase1_dh_group_numbers = optional(list(string), [2, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24])
phase1_encryption_algorithms = optional(list(string), ["AES128", "AES256", "AES128-GCM-16", "AES256-GCM-16"])
phase1_integrity_algorithms = optional(list(string), ["SHA1", "SHA2-256", "SHA2-384", "SHA2-512"])
phase1_lifetime_seconds = optional(number, 28800)
phase2_dh_group_numbers = optional(list(string), [2, 5, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24])
phase2_encryption_algorithms = optional(list(string), ["AES128", "AES256", "AES128-GCM-16", "AES256-GCM-16"])
phase2_integrity_algorithms = optional(list(string), ["SHA1", "SHA2-256", "SHA2-384", "SHA2-512"])
phase2_lifetime_seconds = optional(number, 3600)
rekey_fuzz_percentage = optional(number, 100)
rekey_margin_time_seconds = optional(number, 540)
replay_window_size = optional(number, 1024)
startup_action = optional(string, "add")
cloudwatch_log_options = optional(object({
enabled = optional(bool, false)
log_group_arn = optional(string, "")
log_output_format = optional(string, "json")
}), {})
}), {})
tunnel2_options = optional(object({
inside_cidr = optional(string, null)
preshared_key = optional(string, null)
dpd_timeout_action = optional(string, "clear")
dpd_timeout_seconds = optional(number, 30)
enable_tunnel_lifecycle_control = optional(bool, false)
ike_versions = optional(list(string), ["ikev1", "ikev2"])
phase1_dh_group_numbers = optional(list(string), [2, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24])
phase1_encryption_algorithms = optional(list(string), ["AES128", "AES256", "AES128-GCM-16", "AES256-GCM-16"])
phase1_integrity_algorithms = optional(list(string), ["SHA1", "SHA2-256", "SHA2-384", "SHA2-512"])
phase1_lifetime_seconds = optional(number, 28800)
phase2_dh_group_numbers = optional(list(string), [2, 5, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24])
phase2_encryption_algorithms = optional(list(string), ["AES128", "AES256", "AES128-GCM-16", "AES256-GCM-16"])
phase2_integrity_algorithms = optional(list(string), ["SHA1", "SHA2-256", "SHA2-384", "SHA2-512"])
phase2_lifetime_seconds = optional(number, 3600)
rekey_fuzz_percentage = optional(number, 100)
rekey_margin_time_seconds = optional(number, 540)
replay_window_size = optional(number, 1024)
startup_action = optional(string, "add")
cloudwatch_log_options = optional(object({
enabled = optional(bool, false)
log_group_arn = optional(string, "")
log_output_format = optional(string, "json")
}), {})
}), {})
})), [])
})

Default: {}

Outputs​

The following outputs are exported:

all_prefix_list_ids_by_name​

Description: List of all prefix lists

customer_managed_prefix_lists​

Description: Map of customer managed prefix lists

dx_gateway_ids_by_name​

Description: Map of direct connect gateways by name

transit_gateway_arn​

Description: ARN of transit gateway.

transit_gateway_id​

Description: Identifier of transit gateway.

transit_gateway_name​

Description: Name of transit gateway.

transit_gateway_peering_info_for_creator​

Description: Information required for transit gateway peering creator.

transit_gateway_route_table_ids​

Description: Identifier of transit gateway route tables by name.

vpn_connections_by_name​

Description: Map of vpn connections by name

vpn_customer_gateways_by_name​

Description: Map of vpn customer gateways by name

vpn_preshared_keys_by_connection_name​

Description: Map of tunnel preshared keys of vpn connections by name