Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow creation of peering attachments #54

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 0 additions & 67 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -34,70 +34,3 @@ data "aws_ec2_transit_gateway" "this" {
count = local.lookup_transit_gateway ? 1 : 0
id = local.transit_gateway_id
}

data "aws_vpc" "default" {
for_each = module.this.enabled && var.create_transit_gateway_vpc_attachment && var.config != null ? var.config : {}
id = each.value["vpc_id"]
}

resource "aws_ec2_transit_gateway_vpc_attachment" "default" {
for_each = module.this.enabled && var.create_transit_gateway_vpc_attachment && var.config != null ? var.config : {}
transit_gateway_id = local.transit_gateway_id
vpc_id = each.value["vpc_id"]
subnet_ids = each.value["subnet_ids"]
appliance_mode_support = var.vpc_attachment_appliance_mode_support
dns_support = var.vpc_attachment_dns_support
ipv6_support = var.vpc_attachment_ipv6_support
tags = module.this.tags

# transit_gateway_default_route_table_association and transit_gateway_default_route_table_propagation
# must be set to `false` if the VPC is in the same account as the Transit Gateway, and `null` otherwise
# https://github.com/terraform-providers/terraform-provider-aws/issues/13512
# https://github.com/terraform-providers/terraform-provider-aws/issues/8383
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_transit_gateway_vpc_attachment
transit_gateway_default_route_table_association = data.aws_ec2_transit_gateway.this[0].owner_id == data.aws_vpc.default[each.key].owner_id ? false : null
transit_gateway_default_route_table_propagation = data.aws_ec2_transit_gateway.this[0].owner_id == data.aws_vpc.default[each.key].owner_id ? false : null
}

# Allow traffic from the VPC attachments to the Transit Gateway
resource "aws_ec2_transit_gateway_route_table_association" "default" {
for_each = module.this.enabled && var.create_transit_gateway_route_table_association_and_propagation && var.config != null ? var.config : {}
transit_gateway_attachment_id = each.value["transit_gateway_vpc_attachment_id"] != null ? each.value["transit_gateway_vpc_attachment_id"] : aws_ec2_transit_gateway_vpc_attachment.default[each.key]["id"]
transit_gateway_route_table_id = local.transit_gateway_route_table_id
}

# Allow traffic from the Transit Gateway to the VPC attachments
# Propagations will create propagated routes
resource "aws_ec2_transit_gateway_route_table_propagation" "default" {
for_each = module.this.enabled && var.create_transit_gateway_route_table_association_and_propagation && var.config != null ? var.config : {}
transit_gateway_attachment_id = each.value["transit_gateway_vpc_attachment_id"] != null ? each.value["transit_gateway_vpc_attachment_id"] : aws_ec2_transit_gateway_vpc_attachment.default[each.key]["id"]
transit_gateway_route_table_id = local.transit_gateway_route_table_id
}

# Static Transit Gateway routes
# Static routes have a higher precedence than propagated routes
# https://docs.aws.amazon.com/vpc/latest/tgw/how-transit-gateways-work.html
# https://docs.aws.amazon.com/vpc/latest/tgw/tgw-route-tables.html
module "transit_gateway_route" {
source = "./modules/transit_gateway_route"
for_each = module.this.enabled && var.create_transit_gateway_route_table_association_and_propagation && var.config != null ? var.config : {}
transit_gateway_attachment_id = each.value["transit_gateway_vpc_attachment_id"] != null ? each.value["transit_gateway_vpc_attachment_id"] : aws_ec2_transit_gateway_vpc_attachment.default[each.key]["id"]
transit_gateway_route_table_id = local.transit_gateway_route_table_id
route_config = each.value["static_routes"] != null ? each.value["static_routes"] : []

depends_on = [aws_ec2_transit_gateway_vpc_attachment.default, aws_ec2_transit_gateway_route_table.default]
}

# Create routes in the subnets' route tables to route traffic from subnets to the Transit Gateway VPC attachments
# Only route to VPCs of the environments defined in `route_to` attribute
module "subnet_route" {
source = "./modules/subnet_route"
for_each = module.this.enabled && var.create_transit_gateway_vpc_attachment && var.config != null ? var.config : {}
transit_gateway_id = local.transit_gateway_id
route_table_ids = each.value["subnet_route_table_ids"] != null ? each.value["subnet_route_table_ids"] : []
destination_cidr_blocks = each.value["route_to_cidr_blocks"] != null ? each.value["route_to_cidr_blocks"] : ([for i in setintersection(keys(var.config), (each.value["route_to"] != null ? each.value["route_to"] : [])) : var.config[i]["vpc_cidr"]])
route_keys_enabled = var.route_keys_enabled
route_timeouts = var.route_timeouts

depends_on = [aws_ec2_transit_gateway.default, data.aws_ec2_transit_gateway.this, aws_ec2_transit_gateway_vpc_attachment.default]
}
4 changes: 2 additions & 2 deletions outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ output "transit_gateway_vpc_attachment_ids" {
}

output "transit_gateway_route_ids" {
value = try({ for i, o in module.transit_gateway_route : i => o["transit_gateway_route_ids"] }, {})
value = merge(try({ for i, o in module.transit_gateway_route_vpc_attachment : i => o["transit_gateway_route_ids"] }, {}), try({ for i, o in module.transit_gateway_route_peering_attachment : i => o["transit_gateway_route_ids"] }, {}))
description = "Transit Gateway route identifiers combined with destinations"
}

output "subnet_route_ids" {
value = try({ for i, o in module.subnet_route : i => o["subnet_route_ids"] }, {})
value = merge(try({ for i, o in module.subnet_route_vpc_attachment : i => o["subnet_route_ids"] }, {}), try({ for i, o in module.subnet_route_peering_attachment : i => o["subnet_route_ids"] }, {}))
description = "Subnet route identifiers combined with destinations"
}

Expand Down
64 changes: 64 additions & 0 deletions peering_attachments.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
locals {
tgw_peering_attachments = { for k, v in var.config : k => v if v.peering_peer_account_id != null }
}

resource "aws_ec2_transit_gateway_peering_attachment" "default" {
for_each = module.this.enabled && var.create_transit_gateway_vpc_attachment && local.tgw_peering_attachments != null ? local.tgw_peering_attachments : {}

transit_gateway_id = local.transit_gateway_id
peer_account_id = each.value["peering_peer_account_id"]
peer_region = each.value["peering_peer_region"]
peer_transit_gateway_id = each.value["peering_peer_transit_gateway_id"]
tags = merge(module.this.tags, { Name = "${module.this.id}${module.this.delimiter}${each.key}${module.this.delimiter}attachment" })

dynamic "options" {
for_each = each.value["peering_enable_dynamic_routing"] != null ? [each.value["peering_enable_dynamic_routing"]] : []

content {
dynamic_routing = options.value ? "enable" : "disable"
}
}
}

# Allow traffic from the VPC attachments to the Transit Gateway
resource "aws_ec2_transit_gateway_route_table_association" "peering_attachment" {
for_each = module.this.enabled && var.create_transit_gateway_route_table_association_and_propagation && local.tgw_peering_attachments != null ? local.tgw_peering_attachments : {}
transit_gateway_attachment_id = each.value["transit_gateway_vpc_attachment_id"] != null ? each.value["transit_gateway_vpc_attachment_id"] : aws_ec2_transit_gateway_peering_attachment.default[each.key]["id"]
transit_gateway_route_table_id = local.transit_gateway_route_table_id
}

# Allow traffic from the Transit Gateway to the VPC attachments
# Propagations will create propagated routes
resource "aws_ec2_transit_gateway_route_table_propagation" "peering_attachment" {
for_each = module.this.enabled && var.create_transit_gateway_route_table_association_and_propagation && local.tgw_peering_attachments != null ? { for k, v in local.tgw_peering_attachments : k => v if v.peering_create_propogation } : {}
transit_gateway_attachment_id = each.value["transit_gateway_vpc_attachment_id"] != null ? each.value["transit_gateway_vpc_attachment_id"] : aws_ec2_transit_gateway_peering_attachment.default[each.key]["id"]
transit_gateway_route_table_id = local.transit_gateway_route_table_id
}

# Static Transit Gateway routes
# Static routes have a higher precedence than propagated routes
# https://docs.aws.amazon.com/vpc/latest/tgw/how-transit-gateways-work.html
# https://docs.aws.amazon.com/vpc/latest/tgw/tgw-route-tables.html
module "transit_gateway_route_peering_attachment" {
source = "./modules/transit_gateway_route"
for_each = module.this.enabled && var.create_transit_gateway_route_table_association_and_propagation && local.tgw_peering_attachments != null ? local.tgw_peering_attachments : {}
transit_gateway_attachment_id = each.value["transit_gateway_vpc_attachment_id"] != null ? each.value["transit_gateway_vpc_attachment_id"] : aws_ec2_transit_gateway_peering_attachment.default[each.key]["id"]
transit_gateway_route_table_id = local.transit_gateway_route_table_id
route_config = each.value["static_routes"] != null ? each.value["static_routes"] : []

depends_on = [aws_ec2_transit_gateway_peering_attachment.default, aws_ec2_transit_gateway_route_table.default]
}

# Create routes in the subnets' route tables to route traffic from subnets to the Transit Gateway VPC attachments
# Only route to VPCs of the environments defined in `route_to` attribute
module "subnet_route_peering_attachment" {
source = "./modules/subnet_route"
for_each = module.this.enabled && var.create_transit_gateway_vpc_attachment && local.tgw_peering_attachments != null ? local.tgw_peering_attachments : {}
transit_gateway_id = local.transit_gateway_id
route_table_ids = each.value["subnet_route_table_ids"] != null ? each.value["subnet_route_table_ids"] : []
destination_cidr_blocks = each.value["route_to_cidr_blocks"] != null ? each.value["route_to_cidr_blocks"] : ([for i in setintersection(keys(local.tgw_peering_attachments), (each.value["route_to"] != null ? each.value["route_to"] : [])) : local.tgw_peering_attachments[i]["vpc_cidr"]])
route_keys_enabled = var.route_keys_enabled
route_timeouts = var.route_timeouts

depends_on = [aws_ec2_transit_gateway.default, data.aws_ec2_transit_gateway.this, aws_ec2_transit_gateway_peering_attachment.default]
}
42 changes: 25 additions & 17 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -34,31 +34,31 @@ variable "ram_principals" {
variable "auto_accept_shared_attachments" {
type = string
default = "enable"
description = "Whether resource attachment requests are automatically accepted. Valid values: `disable`, `enable`. Default value: `disable`"
description = "Whether resource attachment requests are automatically accepted. Valid values: `disable`, `enable`"
}

variable "default_route_table_association" {
type = string
default = "disable"
description = "Whether resource attachments are automatically associated with the default association route table. Valid values: `disable`, `enable`. Default value: `disable`"
description = "Whether resource attachments are automatically associated with the default association route table. Valid values: `disable`, `enable`"
}

variable "default_route_table_propagation" {
type = string
default = "disable"
description = "Whether resource attachments automatically propagate routes to the default propagation route table. Valid values: `disable`, `enable`. Default value: `disable`"
description = "Whether resource attachments automatically propagate routes to the default propagation route table. Valid values: `disable`, `enable`"
}

variable "dns_support" {
type = string
default = "enable"
description = "Whether resource attachments automatically propagate routes to the default propagation route table. Valid values: `disable`, `enable`. Default value: `enable`"
description = "Whether resource attachments automatically propagate routes to the default propagation route table. Valid values: `disable`, `enable`"
}

variable "vpn_ecmp_support" {
type = string
default = "enable"
description = "Whether resource attachments automatically propagate routes to the default propagation route table. Valid values: `disable`, `enable`. Default value: `enable`"
description = "Whether resource attachments automatically propagate routes to the default propagation route table. Valid values: `disable`, `enable`"
}

variable "allow_external_principals" {
Expand All @@ -76,31 +76,39 @@ variable "vpc_attachment_appliance_mode_support" {
variable "vpc_attachment_dns_support" {
type = string
default = "enable"
description = "Whether resource attachments automatically propagate routes to the default propagation route table. Valid values: `disable`, `enable`. Default value: `enable`"
description = "Whether resource attachments automatically propagate routes to the default propagation route table. Valid values: `disable`, `enable`"
}

variable "vpc_attachment_ipv6_support" {
type = string
default = "disable"
description = "Whether resource attachments automatically propagate routes to the default propagation route table. Valid values: `disable`, `enable`. Default value: `enable`"
description = "Whether resource attachments automatically propagate routes to the default propagation route table. Valid values: `disable`, `enable`"
}

variable "config" {
type = map(object({
vpc_id = string
vpc_cidr = string
subnet_ids = set(string)
subnet_route_table_ids = set(string)
route_to = set(string)
route_to_cidr_blocks = set(string)
transit_gateway_vpc_attachment_id = string
static_routes = set(object({
vpc_id = optional(string)
vpc_cidr = optional(string)
subnet_ids = optional(set(string))
subnet_route_table_ids = optional(set(string))
route_to_cidr_blocks = optional(set(string))
transit_gateway_default_route_table_association = optional(bool)
transit_gateway_default_route_table_propagation = optional(bool)
transit_gateway_vpc_attachment_id = optional(string)
route_to = optional(set(string))
static_routes = optional(set(object({
blackhole = bool
destination_cidr_block = string
}))
})))

peering_peer_account_id = optional(string)
peering_peer_region = optional(string)
peering_peer_transit_gateway_id = optional(string)
peering_enable_dynamic_routing = optional(bool)
peering_create_propogation = optional(bool, false)
}))

description = "Configuration for VPC attachments, Transit Gateway routes, and subnet routes"
description = "Configuration for VPC attachments, peering attachments, Transit Gateway routes, and subnet routes"
default = null
}

Expand Down
60 changes: 60 additions & 0 deletions vpc_attachments.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
locals {
tgw_vpc_attachments = { for k, v in var.config : k => v if v.vpc_id != null }
}

resource "aws_ec2_transit_gateway_vpc_attachment" "default" {
for_each = module.this.enabled && var.create_transit_gateway_vpc_attachment && local.tgw_vpc_attachments != null ? local.tgw_vpc_attachments : {}
transit_gateway_id = local.transit_gateway_id
vpc_id = each.value["vpc_id"]
subnet_ids = each.value["subnet_ids"]
appliance_mode_support = var.vpc_attachment_appliance_mode_support
dns_support = var.vpc_attachment_dns_support
ipv6_support = var.vpc_attachment_ipv6_support
tags = merge(module.this.tags, { Name = "${module.this.id}${module.this.delimiter}${each.key}${module.this.delimiter}attachment" })

transit_gateway_default_route_table_association = each.value["transit_gateway_default_route_table_association"]
transit_gateway_default_route_table_propagation = each.value["transit_gateway_default_route_table_propagation"]
}

# Allow traffic from the VPC attachments to the Transit Gateway
resource "aws_ec2_transit_gateway_route_table_association" "vpc_attachment" {
for_each = module.this.enabled && var.create_transit_gateway_route_table_association_and_propagation && local.tgw_vpc_attachments != null ? local.tgw_vpc_attachments : {}
transit_gateway_attachment_id = each.value["transit_gateway_vpc_attachment_id"] != null ? each.value["transit_gateway_vpc_attachment_id"] : aws_ec2_transit_gateway_vpc_attachment.default[each.key]["id"]
transit_gateway_route_table_id = local.transit_gateway_route_table_id
}

# Allow traffic from the Transit Gateway to the VPC attachments
# Propagations will create propagated routes
resource "aws_ec2_transit_gateway_route_table_propagation" "vpc_attachment" {
for_each = module.this.enabled && var.create_transit_gateway_route_table_association_and_propagation && local.tgw_vpc_attachments != null ? local.tgw_vpc_attachments : {}
transit_gateway_attachment_id = each.value["transit_gateway_vpc_attachment_id"] != null ? each.value["transit_gateway_vpc_attachment_id"] : aws_ec2_transit_gateway_vpc_attachment.default[each.key]["id"]
transit_gateway_route_table_id = local.transit_gateway_route_table_id
}

# Static Transit Gateway routes
# Static routes have a higher precedence than propagated routes
# https://docs.aws.amazon.com/vpc/latest/tgw/how-transit-gateways-work.html
# https://docs.aws.amazon.com/vpc/latest/tgw/tgw-route-tables.html
module "transit_gateway_route_vpc_attachment" {
source = "./modules/transit_gateway_route"
for_each = module.this.enabled && var.create_transit_gateway_route_table_association_and_propagation && local.tgw_vpc_attachments != null ? local.tgw_vpc_attachments : {}
transit_gateway_attachment_id = each.value["transit_gateway_vpc_attachment_id"] != null ? each.value["transit_gateway_vpc_attachment_id"] : aws_ec2_transit_gateway_vpc_attachment.default[each.key]["id"]
transit_gateway_route_table_id = local.transit_gateway_route_table_id
route_config = each.value["static_routes"] != null ? each.value["static_routes"] : []

depends_on = [aws_ec2_transit_gateway_vpc_attachment.default, aws_ec2_transit_gateway_route_table.default]
}

# Create routes in the subnets' route tables to route traffic from subnets to the Transit Gateway VPC attachments
# Only route to VPCs of the environments defined in `route_to` attribute
module "subnet_route_vpc_attachment" {
source = "./modules/subnet_route"
for_each = module.this.enabled && var.create_transit_gateway_vpc_attachment && local.tgw_vpc_attachments != null ? local.tgw_vpc_attachments : {}
transit_gateway_id = local.transit_gateway_id
route_table_ids = each.value["subnet_route_table_ids"] != null ? each.value["subnet_route_table_ids"] : []
destination_cidr_blocks = each.value["route_to_cidr_blocks"] != null ? each.value["route_to_cidr_blocks"] : ([for i in setintersection(keys(local.tgw_vpc_attachments), (each.value["route_to"] != null ? each.value["route_to"] : [])) : local.tgw_vpc_attachments[i]["vpc_cidr"]])
route_keys_enabled = var.route_keys_enabled
route_timeouts = var.route_timeouts

depends_on = [aws_ec2_transit_gateway.default, data.aws_ec2_transit_gateway.this, aws_ec2_transit_gateway_vpc_attachment.default]
}