Skip to content

Commit

Permalink
Add routes for VPC + Subnet IPv6 space (#116)
Browse files Browse the repository at this point in the history
* Add routes for VPC + Subnet IPv6 space

VPC's can be setup as dual stack which will allow for them to have ipv6
addresses as well as ipv4 ones. This will make it so if vpc's get paried
that do have ipv6 addressing on them that the route tables also get
setup with the ipv6 addresses.

* Add a test for when only 1 side has ipv6 addresses
  • Loading branch information
Unverified authored Jun 1, 2024
1 parent 0f63b61 commit 742ce9f
Show file tree
Hide file tree
Showing 17 changed files with 341 additions and 84 deletions.
1 change: 0 additions & 1 deletion docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
---
version: "3.8"
services:
localstack:
container_name: "${LOCALSTACK_DOCKER_NAME:-localstack-main}"
Expand Down
50 changes: 25 additions & 25 deletions examples/partial-subnets/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@

# peer vpc main route table
data "aws_route_table" "peer_main_route_table" {
provider = aws.peer
provider = aws.peer
vpc_id = var.peer_vpc_id
filter {
name = "association.main"
values = ["true"]
}
}
}

# peer subnets
data "aws_subnets" "peer" {
provider = aws.peer
provider = aws.peer
filter {
name = "vpc-id"
values = [var.peer_vpc_id]
Expand All @@ -23,7 +23,7 @@ data "aws_subnets" "peer" {

# get route tables associated with subnets
data "aws_route_tables" "peer_associated_route_tables" {
for_each = { for subnet in data.aws_subnets.peer.ids: subnet => subnet }
for_each = { for subnet in data.aws_subnets.peer.ids : subnet => subnet }
provider = aws.peer
vpc_id = var.peer_vpc_id
filter {
Expand All @@ -34,37 +34,37 @@ data "aws_route_tables" "peer_associated_route_tables" {

locals {
peer_subnet_route_table_map = {
for subnet in data.aws_subnets.peer.ids:
subnet => concat(
data.aws_route_tables.peer_associated_route_tables[subnet].ids,
[data.aws_route_table.peer_main_route_table.id]
)[0]
for subnet in data.aws_subnets.peer.ids :
subnet => concat(
data.aws_route_tables.peer_associated_route_tables[subnet].ids,
[data.aws_route_table.peer_main_route_table.id]
)[0]
}
peer_subnets_associated_map = {
for subnet, route_table in local.peer_subnet_route_table_map:
subnet => route_table
if route_table != data.aws_route_table.peer_main_route_table.id
for subnet, route_table in local.peer_subnet_route_table_map :
subnet => route_table
if route_table != data.aws_route_table.peer_main_route_table.id
}

peer_subnets_unassociated_map = {
for subnet, route_table in local.peer_subnet_route_table_map:
subnet => route_table
if route_table == data.aws_route_table.peer_main_route_table.id
for subnet, route_table in local.peer_subnet_route_table_map :
subnet => route_table
if route_table == data.aws_route_table.peer_main_route_table.id
}
peer_subnet_ids = distinct(concat(
try(slice(keys(local.peer_subnets_associated_map), 0, 1), []),
try(slice(keys(local.peer_subnets_unassociated_map),0, 1), []),
try(slice(keys(local.peer_subnets_unassociated_map), 0, 1), []),
))
# actually, peer route tables should be detected from peer subnets if specified
peer_route_tables = distinct([ for subnet in local.peer_subnet_ids: local.peer_subnet_route_table_map[subnet] ])
peer_route_tables = distinct([for subnet in local.peer_subnet_ids : local.peer_subnet_route_table_map[subnet]])
}




module "partial_subnets" {
source = "../../"

source = "../../"
#version = "6.0.0"

providers = {
Expand All @@ -77,15 +77,15 @@ module "partial_subnets" {

auto_accept_peering = true
peer_dns_resolution = true
this_dns_resolution = true
peer_subnets_ids = length(var.peer_subnets_ids) > 0 ? var.peer_subnets_ids : local.peer_subnet_ids
this_subnets_ids = var.this_subnets_ids
this_rts_ids = var.this_rts_ids
peer_rts_ids = length(var.peer_rts_ids)>0 ? var.peer_rts_ids : local.peer_route_tables
this_dns_resolution = true
peer_subnets_ids = length(var.peer_subnets_ids) > 0 ? var.peer_subnets_ids : local.peer_subnet_ids
this_subnets_ids = var.this_subnets_ids
this_rts_ids = var.this_rts_ids
peer_rts_ids = length(var.peer_rts_ids) > 0 ? var.peer_rts_ids : local.peer_route_tables

tags = {
Name = "tf-partial-subnets"
Environment = "Test"
}

}
32 changes: 16 additions & 16 deletions examples/partial-subnets/variables.tf
Original file line number Diff line number Diff line change
@@ -1,50 +1,50 @@
variable this_assume_role_arn {
type = string
variable "this_assume_role_arn" {
type = string
default = ""
}

variable peer_assume_role_arn {
type = string
variable "peer_assume_role_arn" {
type = string
default = ""
}

variable "aws_this_access_key" {
description = "AWS Access Key for requester account"
default = ""
default = ""
}

variable "aws_this_secret_key" {
description = "AWS Secret Key for requester account"
default = ""
default = ""
}

variable "aws_peer_access_key" {
description = "AWS Access Key for accepter account"
default = ""
default = ""
}

variable "aws_peer_secret_key" {
description = "AWS Secret Key for accepter account"
default = ""
default = ""
}


variable this_region {
type = string
variable "this_region" {
type = string
default = "eu-central-1"
}

variable peer_region {
type = string
variable "peer_region" {
type = string
default = "eu-central-1"
}

variable this_vpc_id {
type = string
variable "this_vpc_id" {
type = string
}

variable peer_vpc_id {
type = string
variable "peer_vpc_id" {
type = string
}

variable "auto_accept_peering" {
Expand Down
4 changes: 2 additions & 2 deletions examples/single-account-single-region-with-options/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ module "single_account_single_region_options" {
auto_accept_peering = true

// Peering options for requester
this_dns_resolution = true
this_dns_resolution = true

// Peering options for accepter
peer_dns_resolution = true
peer_dns_resolution = true

tags = {
Name = "tf-single-account-single-region-with-options"
Expand Down
48 changes: 30 additions & 18 deletions locals.tf
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ locals {
this_region = data.aws_region.this.name
peer_region = data.aws_region.peer.name

same_region = data.aws_region.this.name == data.aws_region.peer.name
same_account = data.aws_caller_identity.this.account_id == data.aws_caller_identity.peer.account_id
same_acount_and_region = local.same_region && local.same_account
same_region = data.aws_region.this.name == data.aws_region.peer.name
same_account = data.aws_caller_identity.this.account_id == data.aws_caller_identity.peer.account_id
same_account_and_region = local.same_region && local.same_account

# Rout table should either be the one for the vpc, or the ones associated to the subnets if subnets are given
this_subnet_route_table_map = {
Expand Down Expand Up @@ -34,44 +34,56 @@ locals {
# `this_dest_cidrs` represent CIDR of peer VPC, therefore a destination CIDR for this_vpc
# `peer_dest_cidrs` represent CIDR of this VPC, therefore a destination CIDR for peer_vpc
# Destination cidrs for this are in peer and vice versa
this_dest_cidrs = length(var.peer_subnets_ids) == 0 ? toset([data.aws_vpc.peer_vpc.cidr_block]) : toset(data.aws_subnet.peer[*].cidr_block)
peer_dest_cidrs = length(var.this_subnets_ids) == 0 ? toset([data.aws_vpc.this_vpc.cidr_block]) : toset(data.aws_subnet.this[*].cidr_block)
this_dest_ipv4_cidrs = toset(compact(length(var.peer_subnets_ids) == 0 ? [data.aws_vpc.peer_vpc.cidr_block] : data.aws_subnet.peer[*].cidr_block))
this_dest_ipv6_cidrs = toset(compact(length(var.peer_subnets_ids) == 0 ? [data.aws_vpc.peer_vpc.ipv6_cidr_block] : data.aws_subnet.peer[*].ipv6_cidr_block))
peer_dest_ipv4_cidrs = toset(compact(length(var.this_subnets_ids) == 0 ? [data.aws_vpc.this_vpc.cidr_block] : data.aws_subnet.this[*].cidr_block))
peer_dest_ipv6_cidrs = toset(compact(length(var.this_subnets_ids) == 0 ? [data.aws_vpc.this_vpc.ipv6_cidr_block] : data.aws_subnet.this[*].ipv6_cidr_block))

# Get associated CIDR blocks
this_associated_dest_cidrs = toset(tolist([for k, v in data.aws_vpc.peer_vpc.cidr_block_associations : v.cidr_block]))
peer_associated_dest_cidrs = toset(tolist([for k, v in data.aws_vpc.this_vpc.cidr_block_associations : v.cidr_block]))
this_associated_dest_cidrs = toset(compact([for k, v in data.aws_vpc.peer_vpc.cidr_block_associations : v.cidr_block]))
peer_associated_dest_cidrs = toset(compact([for k, v in data.aws_vpc.this_vpc.cidr_block_associations : v.cidr_block]))

# Allow specifying route tables explicitly
this_rts_ids_hack = length(var.this_rts_ids) == 0 ? local.this_rts_ids : var.this_rts_ids
peer_rts_ids_hack = length(var.peer_rts_ids) == 0 ? local.peer_rts_ids : var.peer_rts_ids

# In each route table there should be 1 route for each subnet, so combining the two sets
this_routes = [
for pair in setproduct(local.this_rts_ids_hack, local.this_dest_cidrs) : {
rts_id = pair[0]
dest_cidr = pair[1]
this_ipv4_routes = [
for pair in setproduct(local.this_rts_ids_hack, local.this_dest_ipv4_cidrs) : {
rts_id = pair[0]
dest_ipv4_cidr = pair[1]
}
]

# In each route table there should be 1 route for each subnet, so combining the two sets
peer_routes = [
for pair in setproduct(local.peer_rts_ids_hack, local.peer_dest_cidrs) : {
rts_id = pair[0]
dest_cidr = pair[1]
this_ipv6_routes = [
for pair in setproduct(local.this_rts_ids_hack, local.this_dest_ipv6_cidrs) : {
rts_id = pair[0]
dest_ipv6_cidr = pair[1]
}
]

peer_ipv4_routes = [
for pair in setproduct(local.peer_rts_ids_hack, local.peer_dest_ipv4_cidrs) : {
rts_id = pair[0]
dest_ipv4_cidr = pair[1]
}
]

peer_ipv6_routes = [
for pair in setproduct(local.peer_rts_ids_hack, local.peer_dest_ipv6_cidrs) : {
rts_id = pair[0]
dest_ipv6_cidr = pair[1]
}
]

# Routes for associated subnets
# Routes for additional associated CIDRs
this_associated_routes = [
for pair in setproduct(local.this_rts_ids_hack, local.this_associated_dest_cidrs) : {
rts_id = pair[0]
dest_cidr = pair[1]
}
]

# In each route table there should be 1 route for each subnet, so combining the two sets
peer_associated_routes = [
for pair in setproduct(local.peer_rts_ids_hack, local.peer_associated_dest_cidrs) : {
rts_id = pair[0]
Expand Down
34 changes: 26 additions & 8 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ resource "aws_vpc_peering_connection" "this" {
peer_vpc_id = var.peer_vpc_id
vpc_id = var.this_vpc_id
peer_region = data.aws_region.peer.name
tags = merge(var.tags, { "Name" = var.name }, tomap({ "Side" = local.same_acount_and_region ? "Both" : "Requester" }))
tags = merge(var.tags, { "Name" = var.name }, tomap({ "Side" = local.same_account_and_region ? "Both" : "Requester" }))
# hardcoded
timeouts {
create = "15m"
Expand All @@ -22,7 +22,7 @@ resource "aws_vpc_peering_connection_accepter" "peer_accepter" {
provider = aws.peer
vpc_peering_connection_id = aws_vpc_peering_connection.this.id
auto_accept = var.auto_accept_peering
tags = merge(var.tags, { "Name" = var.name }, tomap({ "Side" = local.same_acount_and_region ? "Both" : "Accepter" }))
tags = merge(var.tags, { "Name" = var.name }, tomap({ "Side" = local.same_account_and_region ? "Both" : "Accepter" }))
}

#######################
Expand Down Expand Up @@ -52,12 +52,21 @@ resource "aws_vpc_peering_connection_options" "accepter" {
resource "aws_route" "this_routes" {
provider = aws.this
# Only create routes for this route table if input dictates it, and in that case, for all combinations
count = local.create_routes_this ? length(local.this_routes) : 0
route_table_id = local.this_routes[count.index].rts_id
destination_cidr_block = local.this_routes[count.index].dest_cidr
count = local.create_routes_this ? length(local.this_ipv4_routes) : 0
route_table_id = local.this_ipv4_routes[count.index].rts_id
destination_cidr_block = local.this_ipv4_routes[count.index].dest_ipv4_cidr
vpc_peering_connection_id = aws_vpc_peering_connection.this.id
}

resource "aws_route" "this_ipv6_routes" {
provider = aws.this
# Only create routes for this route table if input dictates it, and in that case, for all combinations
count = local.create_routes_this ? length(local.this_ipv6_routes) : 0
route_table_id = local.this_ipv6_routes[count.index].rts_id
destination_ipv6_cidr_block = local.this_ipv6_routes[count.index].dest_ipv6_cidr
vpc_peering_connection_id = aws_vpc_peering_connection.this.id
}

###################
# This VPC Associated Routes # Routes from THIS route table to associated PEER CIDR
###################
Expand All @@ -76,12 +85,21 @@ resource "aws_route" "this_associated_routes" {
resource "aws_route" "peer_routes" {
provider = aws.peer
# Only create routes for peer route table if input dictates it, and in that case, for all combinations
count = local.create_routes_peer ? length(local.peer_routes) : 0
route_table_id = local.peer_routes[count.index].rts_id
destination_cidr_block = local.peer_routes[count.index].dest_cidr
count = local.create_routes_peer ? length(local.peer_ipv4_routes) : 0
route_table_id = local.peer_ipv4_routes[count.index].rts_id
destination_cidr_block = local.peer_ipv4_routes[count.index].dest_ipv4_cidr
vpc_peering_connection_id = aws_vpc_peering_connection.this.id
}

resource "aws_route" "peer_ipv6_routes" {
provider = aws.peer
# Only create routes for peer route table if input dictates it, and in that case, for all combinations
count = local.create_routes_peer ? length(local.peer_ipv6_routes) : 0
route_table_id = local.peer_ipv6_routes[count.index].rts_id
destination_ipv6_cidr_block = local.peer_ipv6_routes[count.index].dest_ipv6_cidr
vpc_peering_connection_id = aws_vpc_peering_connection.this.id
}

###################
# Peer VPC Associated Routes # Routes from PEER route table to THIS CIDR
###################
Expand Down
Loading

0 comments on commit 742ce9f

Please sign in to comment.