diff --git a/modules/route-table/README.md b/modules/route-table/README.md index ae21618..a6b7eb4 100644 --- a/modules/route-table/README.md +++ b/modules/route-table/README.md @@ -14,14 +14,14 @@ This module creates following resources. | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 1.5 | -| [aws](#requirement\_aws) | >= 4.22 | +| [terraform](#requirement\_terraform) | >= 1.6 | +| [aws](#requirement\_aws) | >= 5.11 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | 5.19.0 | +| [aws](#provider\_aws) | 5.23.1 | ## Modules @@ -50,28 +50,34 @@ This module creates following resources. | [name](#input\_name) | (Required) Desired name for the route table resources. | `string` | n/a | yes | | [vpc\_id](#input\_vpc\_id) | (Required) The ID of the VPC which the route table belongs to. | `string` | n/a | yes | | [gateways](#input\_gateways) | (Optional) A list of gateway IDs to associate with the route table. Only support Internet Gateway and Virtual Private Gateway. | `list(string)` | `[]` | no | -| [ipv4\_routes](#input\_ipv4\_routes) | (Optional) A list of route rules for IPv4 CIDRs. | `list(map(string))` | `[]` | no | -| [ipv6\_routes](#input\_ipv6\_routes) | (Optional) A list of route rules for IPv6 CIDRs. | `list(map(string))` | `[]` | no | -| [is\_main](#input\_is\_main) | (Optional) Whether to set this route table as the main route table. | `bool` | `false` | no | +| [ipv4\_routes](#input\_ipv4\_routes) | (Optional) A list of route rules for destinations to IPv4 CIDRs. Each block of `ipv4_routes` as defined below.
(Required) `destination` - The destination IPv4 CIDR block of the route rule.
(Required) `target` - A configuration of the target of the route rule. `target` as defined below.
(Required) `type` - The type of the target of the route rule. Valid values are `CARRIER_GATEWAY`, `CORE_GATEWAY`, `EGRESS_ONLY_INTERNET_GATEWAY`, `INTERNET_GATEWAY`, `VPN_GATEWAY`, `LOCAL_GATEWAY`, `NAT_GATEWAY`, `NETWORK_INTERFACE`, `TRANSIT_GATEWAY`, `VPC_ENDPOINT`, `VPC_PEERING_CONNECTION`.
(Required) `id` - The ID of the target of the route rule. |
list(object({
destination = string

target = object({
type = string
id = string
})
}))
| `[]` | no | +| [ipv6\_routes](#input\_ipv6\_routes) | (Optional) A list of route rules for destinations to IPv6 CIDRs. Each block of `ipv6_routes` as defined below.
(Required) `destination` - The destination IPv6 CIDR block of the route rule.
(Required) `target` - A configuration of the target of the route rule. `target` as defined below.
(Required) `type` - The type of the target of the route rule. Valid values are `CARRIER_GATEWAY`, `CORE_GATEWAY`, `EGRESS_ONLY_INTERNET_GATEWAY`, `INTERNET_GATEWAY`, `VPN_GATEWAY`, `LOCAL_GATEWAY`, `NAT_GATEWAY`, `NETWORK_INTERFACE`, `TRANSIT_GATEWAY`, `VPC_ENDPOINT`, `VPC_PEERING_CONNECTION`.
(Required) `id` - The ID of the target of the route rule. |
list(object({
destination = string

target = object({
type = string
id = string
})
}))
| `[]` | no | +| [is\_main](#input\_is\_main) | (Optional) Whether to set this route table as the main route table. Defaults to `false`. | `bool` | `false` | no | | [module\_tags\_enabled](#input\_module\_tags\_enabled) | (Optional) Whether to create AWS Resource Tags for the module informations. | `bool` | `true` | no | -| [prefix\_list\_routes](#input\_prefix\_list\_routes) | (Optional) A list of route rules for Managed Prefix List. | `list(map(string))` | `[]` | no | +| [prefix\_list\_routes](#input\_prefix\_list\_routes) | (Optional) A list of route rules for destinations to Prefix Lists. Each block of `prefix_list_routes` as defined below.
(Required) `name` - The name of the route rule.
(Required) `destination` - The destination Prefix List of the route rule.
(Required) `target` - A configuration of the target of the route rule. `target` as defined below.
(Required) `type` - The type of the target of the route rule. Valid values are `CARRIER_GATEWAY`, `CORE_GATEWAY`, `EGRESS_ONLY_INTERNET_GATEWAY`, `INTERNET_GATEWAY`, `VPN_GATEWAY`, `LOCAL_GATEWAY`, `NAT_GATEWAY`, `NETWORK_INTERFACE`, `TRANSIT_GATEWAY`, `VPC_ENDPOINT`, `VPC_PEERING_CONNECTION`.
(Required) `id` - The ID of the target of the route rule. |
list(object({
name = string
destination = string

target = object({
type = string
id = string
})
}))
| `[]` | no | | [propagating\_vpn\_gateways](#input\_propagating\_vpn\_gateways) | (Optional) A list of Virtual Private Gateway IDs to propagate routes from. | `list(string)` | `[]` | no | | [resource\_group\_description](#input\_resource\_group\_description) | (Optional) The description of Resource Group. | `string` | `"Managed by Terraform."` | no | | [resource\_group\_enabled](#input\_resource\_group\_enabled) | (Optional) Whether to create Resource Group to find and group AWS resources which are created by this module. | `bool` | `true` | no | | [resource\_group\_name](#input\_resource\_group\_name) | (Optional) The name of Resource Group. A Resource Group name can have a maximum of 127 characters, including letters, numbers, hyphens, dots, and underscores. The name cannot start with `AWS` or `aws`. | `string` | `""` | no | | [subnets](#input\_subnets) | (Optional) A list of subnet IDs to associate with the route table. | `list(string)` | `[]` | no | | [tags](#input\_tags) | (Optional) A map of tags to add to all resources. | `map(string)` | `{}` | no | +| [timeouts](#input\_timeouts) | (Optional) How long to wait for the route table to be created/updated/deleted. |
object({
create = optional(string, "5m")
update = optional(string, "2m")
delete = optional(string, "5m")
})
| `{}` | no | | [vpc\_gateway\_endpoints](#input\_vpc\_gateway\_endpoints) | (Optional) A list of the VPC Endpoint IDs with which the Route Table will be associated. | `list(string)` | `[]` | no | ## Outputs | Name | Description | |------|-------------| +| [arn](#output\_arn) | The ARN of the routing table. | | [associated\_gateways](#output\_associated\_gateways) | A list of gateway IDs which is associated with the route table. | | [associated\_subnets](#output\_associated\_subnets) | A list of subnet IDs which is associated with the route table. | | [associated\_vpc\_gateway\_endpoints](#output\_associated\_vpc\_gateway\_endpoints) | A list of the VPC Gateway Endpoint IDs which is associated with the route table. | | [id](#output\_id) | The ID of the routing table. | +| [ipv4\_routes](#output\_ipv4\_routes) | A list of route rules for destinations to IPv4 CIDRs. | +| [ipv6\_routes](#output\_ipv6\_routes) | A list of route rules for destinations to IPv6 CIDRs. | | [is\_main](#output\_is\_main) | Whether to set this route table as the main route table. | +| [owner](#output\_owner) | The ID of the AWS account that owns subnets in the routing table. | +| [prefix\_list\_routes](#output\_prefix\_list\_routes) | A list of route rules for destinations to Prefix Lists. | | [propagated\_vpn\_gateways](#output\_propagated\_vpn\_gateways) | A list of Virtual Private Gateway IDs which propagate routes from. | | [vpc\_id](#output\_vpc\_id) | The ID of the VPC which the route table belongs to. | diff --git a/modules/route-table/main.tf b/modules/route-table/main.tf index bf45d07..c676e8e 100644 --- a/modules/route-table/main.tf +++ b/modules/route-table/main.tf @@ -14,9 +14,20 @@ locals { } : {} } + +################################################### +# Route Table +################################################### + resource "aws_route_table" "this" { vpc_id = var.vpc_id + timeouts { + create = var.timeouts.create + update = var.timeouts.update + delete = var.timeouts.delete + } + tags = merge( { "Name" = local.metadata.name @@ -24,6 +35,10 @@ resource "aws_route_table" "this" { local.module_tags, var.tags, ) + + lifecycle { + create_before_destroy = true + } } resource "aws_main_route_table_association" "this" { @@ -31,76 +46,12 @@ resource "aws_main_route_table_association" "this" { vpc_id = var.vpc_id route_table_id = aws_route_table.this.id -} - - -################################################### -# Routes -################################################### - -# INFO: Not supported attributes -# - `instance_id` (Deprecated) -resource "aws_route" "ipv4" { - for_each = { - for route in var.ipv4_routes : - route.cidr_block => route - } - - route_table_id = aws_route_table.this.id - destination_cidr_block = each.key - - carrier_gateway_id = try(each.value.carrier_gateway_id, null) - core_network_arn = try(each.value.core_network_arn, null) - egress_only_gateway_id = try(each.value.egress_only_gateway_id, null) - gateway_id = try(each.value.gateway_id, null) - local_gateway_id = try(each.value.local_gateway_id, null) - nat_gateway_id = try(each.value.nat_gateway_id, null) - network_interface_id = try(each.value.network_interface_id, null) - transit_gateway_id = try(each.value.transit_gateway_id, null) - vpc_endpoint_id = try(each.value.vpc_endpoint_id, null) - vpc_peering_connection_id = try(each.value.vpc_peering_connection_id, null) -} -resource "aws_route" "ipv6" { - for_each = { - for route in var.ipv6_routes : - route.cidr => route + timeouts { + create = var.timeouts.create + update = var.timeouts.update + delete = var.timeouts.delete } - - route_table_id = aws_route_table.this.id - destination_ipv6_cidr_block = each.key - - carrier_gateway_id = try(each.value.carrier_gateway_id, null) - core_network_arn = try(each.value.core_network_arn, null) - egress_only_gateway_id = try(each.value.egress_only_gateway_id, null) - gateway_id = try(each.value.gateway_id, null) - local_gateway_id = try(each.value.local_gateway_id, null) - nat_gateway_id = try(each.value.nat_gateway_id, null) - network_interface_id = try(each.value.network_interface_id, null) - transit_gateway_id = try(each.value.transit_gateway_id, null) - vpc_endpoint_id = try(each.value.vpc_endpoint_id, null) - vpc_peering_connection_id = try(each.value.vpc_peering_connection_id, null) -} - -resource "aws_route" "prefix_list" { - for_each = { - for route in var.prefix_list_routes : - route.id => route - } - - route_table_id = aws_route_table.this.id - destination_prefix_list_id = each.key - - carrier_gateway_id = try(each.value.carrier_gateway_id, null) - core_network_arn = try(each.value.core_network_arn, null) - egress_only_gateway_id = try(each.value.egress_only_gateway_id, null) - gateway_id = try(each.value.gateway_id, null) - local_gateway_id = try(each.value.local_gateway_id, null) - nat_gateway_id = try(each.value.nat_gateway_id, null) - network_interface_id = try(each.value.network_interface_id, null) - transit_gateway_id = try(each.value.transit_gateway_id, null) - vpc_endpoint_id = try(each.value.vpc_endpoint_id, null) - vpc_peering_connection_id = try(each.value.vpc_peering_connection_id, null) } diff --git a/modules/route-table/outputs.tf b/modules/route-table/outputs.tf index e18686e..7bfa23c 100644 --- a/modules/route-table/outputs.tf +++ b/modules/route-table/outputs.tf @@ -8,6 +8,100 @@ output "id" { value = aws_route_table.this.id } +output "arn" { + description = "The ARN of the routing table." + value = aws_route_table.this.arn +} + +output "owner" { + description = "The ID of the AWS account that owns subnets in the routing table." + value = aws_route_table.this.owner_id +} + +output "is_main" { + description = "Whether to set this route table as the main route table." + value = var.is_main +} + +output "ipv4_routes" { + description = "A list of route rules for destinations to IPv4 CIDRs." + value = [ + for route in var.ipv4_routes : { + destination = route.destination + target = { + id = aws_route.ipv4[route.destination].id, + state = aws_route.ipv4[route.destination].state, + type = route.target.type + id = coalesce( + aws_route.ipv4[route.destination].carrier_gateway_id, + aws_route.ipv4[route.destination].core_network_arn, + aws_route.ipv4[route.destination].egress_only_gateway_id, + aws_route.ipv4[route.destination].gateway_id, + aws_route.ipv4[route.destination].local_gateway_id, + aws_route.ipv4[route.destination].nat_gateway_id, + aws_route.ipv4[route.destination].network_interface_id, + aws_route.ipv4[route.destination].transit_gateway_id, + aws_route.ipv4[route.destination].vpc_endpoint_id, + aws_route.ipv4[route.destination].vpc_peering_connection_id, + ) + } + } + ] +} + +output "ipv6_routes" { + description = "A list of route rules for destinations to IPv6 CIDRs." + value = [ + for route in var.ipv6_routes : { + destination = route.destination + target = { + id = aws_route.ipv6[route.destination].id, + state = aws_route.ipv6[route.destination].state, + type = route.target.type + id = coalesce( + aws_route.ipv6[route.destination].carrier_gateway_id, + aws_route.ipv6[route.destination].core_network_arn, + aws_route.ipv6[route.destination].egress_only_gateway_id, + aws_route.ipv6[route.destination].gateway_id, + aws_route.ipv6[route.destination].local_gateway_id, + aws_route.ipv6[route.destination].nat_gateway_id, + aws_route.ipv6[route.destination].network_interface_id, + aws_route.ipv6[route.destination].transit_gateway_id, + aws_route.ipv6[route.destination].vpc_endpoint_id, + aws_route.ipv6[route.destination].vpc_peering_connection_id, + ) + } + } + ] +} + +output "prefix_list_routes" { + description = "A list of route rules for destinations to Prefix Lists." + value = [ + for route in var.prefix_list_routes : { + destination = route.destination + target = { + id = aws_route.prefix_list[route.destination].id, + state = aws_route.prefix_list[route.destination].state, + type = route.target.type + id = coalesce( + aws_route.prefix_list[route.destination].carrier_gateway_id, + aws_route.prefix_list[route.destination].core_network_arn, + aws_route.prefix_list[route.destination].egress_only_gateway_id, + aws_route.prefix_list[route.destination].gateway_id, + aws_route.prefix_list[route.destination].local_gateway_id, + aws_route.prefix_list[route.destination].nat_gateway_id, + aws_route.prefix_list[route.destination].network_interface_id, + aws_route.prefix_list[route.destination].transit_gateway_id, + aws_route.prefix_list[route.destination].vpc_endpoint_id, + aws_route.prefix_list[route.destination].vpc_peering_connection_id, + ) + } + } + ] +} + + output "associated_subnets" { description = "A list of subnet IDs which is associated with the route table." value = aws_route_table_association.subnets[*].subnet_id @@ -28,7 +122,3 @@ output "propagated_vpn_gateways" { value = values(aws_vpn_gateway_route_propagation.this)[*].vpn_gateway_id } -output "is_main" { - description = "Whether to set this route table as the main route table." - value = var.is_main -} diff --git a/modules/route-table/routes.tf b/modules/route-table/routes.tf new file mode 100644 index 0000000..8245014 --- /dev/null +++ b/modules/route-table/routes.tf @@ -0,0 +1,174 @@ +################################################### +# IPv4 Routes +################################################### + +# INFO: Not supported attributes +# - `instance_id` (Deprecated) +resource "aws_route" "ipv4" { + for_each = { + for route in var.ipv4_routes : + route.destination => route + } + + route_table_id = aws_route_table.this.id + destination_cidr_block = each.key + + + ## Targets + carrier_gateway_id = (each.value.target.type == "CARRIER_GATEWAY" + ? each.value.target.id + : null + ) + core_network_arn = (each.value.target.type == "CORE_NETWORK" + ? each.value.target.id + : null + ) + egress_only_gateway_id = (each.value.target.type == "EGRESS_ONLY_INTERNET_GATEWAY" + ? each.value.target.id + : null + ) + gateway_id = (contains(["INTERNET_GATEWAY", "VPN_GATEWAY"], each.value.target.type) + ? each.value.target.id + : null + ) + local_gateway_id = (each.value.target.type == "LOCAL_GATEWAY" + ? each.value.target.id + : null + ) + nat_gateway_id = (each.value.target.type == "NAT_GATEWAY" + ? each.value.target.id + : null + ) + network_interface_id = (each.value.target.type == "NETWORK_INTERFACE" + ? each.value.target.id + : null + ) + transit_gateway_id = (each.value.target.type == "TRANSIT_GATEWAY" + ? each.value.target.id + : null + ) + vpc_endpoint_id = (each.value.target.type == "VPC_ENDPOINT" + ? each.value.target.id + : null + ) + vpc_peering_connection_id = (each.value.target.type == "VPC_PEERING_CONNECTION" + ? each.value.target.id + : null + ) +} + + +################################################### +# IPv6 Routes +################################################### + +resource "aws_route" "ipv6" { + for_each = { + for route in var.ipv6_routes : + route.destination => route + } + + route_table_id = aws_route_table.this.id + destination_ipv6_cidr_block = each.key + + + ## Targets + carrier_gateway_id = (each.value.target.type == "CARRIER_GATEWAY" + ? each.value.target.id + : null + ) + core_network_arn = (each.value.target.type == "CORE_NETWORK" + ? each.value.target.id + : null + ) + egress_only_gateway_id = (each.value.target.type == "EGRESS_ONLY_INTERNET_GATEWAY" + ? each.value.target.id + : null + ) + gateway_id = (contains(["INTERNET_GATEWAY", "VPN_GATEWAY"], each.value.target.type) + ? each.value.target.id + : null + ) + local_gateway_id = (each.value.target.type == "LOCAL_GATEWAY" + ? each.value.target.id + : null + ) + nat_gateway_id = (each.value.target.type == "NAT_GATEWAY" + ? each.value.target.id + : null + ) + network_interface_id = (each.value.target.type == "NETWORK_INTERFACE" + ? each.value.target.id + : null + ) + transit_gateway_id = (each.value.target.type == "TRANSIT_GATEWAY" + ? each.value.target.id + : null + ) + vpc_endpoint_id = (each.value.target.type == "VPC_ENDPOINT" + ? each.value.target.id + : null + ) + vpc_peering_connection_id = (each.value.target.type == "VPC_PEERING_CONNECTION" + ? each.value.target.id + : null + ) +} + + +################################################### +# Prefix List Routes +################################################### + +resource "aws_route" "prefix_list" { + for_each = { + for route in var.prefix_list_routes : + route.name => route + } + + route_table_id = aws_route_table.this.id + destination_prefix_list_id = each.value.destination + + + ## Targets + carrier_gateway_id = (each.value.target.type == "CARRIER_GATEWAY" + ? each.value.target.id + : null + ) + core_network_arn = (each.value.target.type == "CORE_NETWORK" + ? each.value.target.id + : null + ) + egress_only_gateway_id = (each.value.target.type == "EGRESS_ONLY_INTERNET_GATEWAY" + ? each.value.target.id + : null + ) + gateway_id = (contains(["INTERNET_GATEWAY", "VPN_GATEWAY"], each.value.target.type) + ? each.value.target.id + : null + ) + local_gateway_id = (each.value.target.type == "LOCAL_GATEWAY" + ? each.value.target.id + : null + ) + nat_gateway_id = (each.value.target.type == "NAT_GATEWAY" + ? each.value.target.id + : null + ) + network_interface_id = (each.value.target.type == "NETWORK_INTERFACE" + ? each.value.target.id + : null + ) + transit_gateway_id = (each.value.target.type == "TRANSIT_GATEWAY" + ? each.value.target.id + : null + ) + vpc_endpoint_id = (each.value.target.type == "VPC_ENDPOINT" + ? each.value.target.id + : null + ) + vpc_peering_connection_id = (each.value.target.type == "VPC_PEERING_CONNECTION" + ? each.value.target.id + : null + ) +} diff --git a/modules/route-table/variables.tf b/modules/route-table/variables.tf index 4ae9bfd..b023837 100644 --- a/modules/route-table/variables.tf +++ b/modules/route-table/variables.tf @@ -10,6 +10,13 @@ variable "vpc_id" { nullable = false } +variable "is_main" { + description = "(Optional) Whether to set this route table as the main route table. Defaults to `false`." + type = bool + default = false + nullable = false +} + variable "subnets" { description = "(Optional) A list of subnet IDs to associate with the route table." type = list(string) @@ -38,32 +45,93 @@ variable "propagating_vpn_gateways" { nullable = false } -variable "is_main" { - description = "(Optional) Whether to set this route table as the main route table." - type = bool - default = false - nullable = false -} - variable "ipv4_routes" { - description = "(Optional) A list of route rules for IPv4 CIDRs." - type = list(map(string)) - default = [] - nullable = false + description = <