diff --git a/modules/tgw/spoke/README.md b/modules/tgw/spoke/README.md index 2afd19e68..fd22e0fc0 100644 --- a/modules/tgw/spoke/README.md +++ b/modules/tgw/spoke/README.md @@ -98,7 +98,10 @@ atmos terraform apply tgw/spoke -s -- ## Providers -No providers. +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | >= 4.1 | +| [aws.tgw-hub](#provider\_aws.tgw-hub) | >= 4.1 | ## Modules @@ -111,10 +114,14 @@ No providers. | [tgw\_hub\_routes](#module\_tgw\_hub\_routes) | cloudposse/transit-gateway/aws | 0.10.0 | | [tgw\_spoke\_vpc\_attachment](#module\_tgw\_spoke\_vpc\_attachment) | ./modules/standard_vpc_attachment | n/a | | [this](#module\_this) | cloudposse/label/null | 0.25.0 | +| [vpc](#module\_vpc) | cloudposse/stack-config/yaml//modules/remote-state | 1.5.0 | ## Resources -No resources. +| Name | Type | +|------|------| +| [aws_route.back_route](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route) | resource | +| [aws_route.default_route](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route) | resource | ## Inputs @@ -124,6 +131,8 @@ No resources. | [attributes](#input\_attributes) | ID element. Additional attributes (e.g. `workers` or `cluster`) to add to `id`,
in the order they appear in the list. New attributes are appended to the
end of the list. The elements of the list are joined by the `delimiter`
and treated as a single ID element. | `list(string)` | `[]` | no | | [connections](#input\_connections) | A list of objects to define each TGW connections.

By default, each connection will look for only the default `vpc` component. |
list(object({
account = object({
stage = string
environment = optional(string, "")
tenant = optional(string, "")
})
vpc_component_names = optional(list(string), ["vpc"])
eks_component_names = optional(list(string), [])
}))
| `[]` | no | | [context](#input\_context) | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"descriptor_formats": {},
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"labels_as_tags": [
"unset"
],
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {},
"tenant": null
}
| no | +| [default\_route\_enabled](#input\_default\_route\_enabled) | Enable default routing via transit gateway, requires also nat gateway and instance to be disabled in vpc component. Default is disabled. | `bool` | `false` | no | +| [default\_route\_outgoing\_account\_name](#input\_default\_route\_outgoing\_account\_name) | The account name which is used for outgoing traffic, when using the transit gateway as default route. | `string` | `null` | no | | [delimiter](#input\_delimiter) | Delimiter to be used between ID elements.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | | [descriptor\_formats](#input\_descriptor\_formats) | Describe additional descriptors to be output in the `descriptors` output map.
Map of maps. Keys are names of descriptors. Values are maps of the form
`{
format = string
labels = list(string)
}`
(Type is `any` so the map values can later be enhanced to provide additional options.)
`format` is a Terraform format string to be passed to the `format()` function.
`labels` is a list of labels, in order, to pass to `format()` function.
Label values will be normalized before being passed to `format()` so they will be
identical to how they appear in `id`.
Default is `{}` (`descriptors` output will be empty). | `any` | `{}` | no | | [enabled](#input\_enabled) | Set to false to prevent the module from creating any resources | `bool` | `null` | no | @@ -142,6 +151,7 @@ No resources. | [regex\_replace\_chars](#input\_regex\_replace\_chars) | Terraform regular expression (regex) string.
Characters matching the regex will be removed from the ID elements.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | | [region](#input\_region) | AWS Region | `string` | n/a | yes | | [stage](#input\_stage) | ID element. Usually used to indicate role, e.g. 'prod', 'staging', 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | +| [static\_routes](#input\_static\_routes) | A list of static routes. |
set(object({
blackhole = bool
destination_cidr_block = string
}))
| `[]` | no | | [tags](#input\_tags) | Additional tags (e.g. `{'BusinessUnit': 'XYZ'}`).
Neither the tag keys nor the tag values will be modified by this module. | `map(string)` | `{}` | no | | [tenant](#input\_tenant) | ID element \_(Rarely used, not included by default)\_. A customer identifier, indicating who this instance of a resource is for | `string` | `null` | no | | [tgw\_hub\_component\_name](#input\_tgw\_hub\_component\_name) | The name of the transit-gateway component | `string` | `"tgw/hub"` | no | diff --git a/modules/tgw/spoke/main.tf b/modules/tgw/spoke/main.tf index 32ef7792e..f03801aac 100644 --- a/modules/tgw/spoke/main.tf +++ b/modules/tgw/spoke/main.tf @@ -8,6 +8,8 @@ locals { spoke_account = module.this.tenant != null ? format("%s-%s-%s", module.this.tenant, module.this.environment, module.this.stage) : format("%s-%s", module.this.environment, module.this.stage) + // "When default routing via transit gateway is enabled, both nat gateway and nat instance must be disabled" + default_route_enabled_and_nat_disabled = module.this.enabled && var.default_route_enabled && length(module.vpc.outputs.nat_gateway_ids) == 0 && length(module.vpc.outputs.nat_instance_ids) == 0 } module "tgw_hub_routes" { @@ -47,7 +49,30 @@ module "tgw_spoke_vpc_attachment" { connections = var.connections expose_eks_sg = var.expose_eks_sg peered_region = var.peered_region - + static_routes = var.static_routes context = module.this.context } + +resource "aws_route" "default_route" { + count = local.default_route_enabled_and_nat_disabled ? length(module.vpc.outputs.private_route_table_ids) : 0 + + route_table_id = module.vpc.outputs.private_route_table_ids[count.index] + destination_cidr_block = "0.0.0.0/0" + transit_gateway_id = module.tgw_hub.outputs.transit_gateway_id +} + +locals { + outgoing_network_account_name = local.default_route_enabled_and_nat_disabled ? format("%s-%s", var.default_route_outgoing_account_name, var.own_vpc_component_name) : "" + default_route_vpc_public_route_table_ids = local.default_route_enabled_and_nat_disabled ? module.tgw_hub.outputs.vpcs[local.outgoing_network_account_name].outputs.default_route_vpc_public_route_table_ids : [] +} + +resource "aws_route" "back_route" { + provider = aws.tgw-hub + + count = local.default_route_enabled_and_nat_disabled ? length(local.default_route_vpc_public_route_table_ids) : 0 + + route_table_id = local.default_route_vpc_public_route_table_ids[count.index] + destination_cidr_block = module.vpc.outputs.vpc_cidr + transit_gateway_id = module.tgw_hub.outputs.transit_gateway_id +} diff --git a/modules/tgw/spoke/modules/standard_vpc_attachment/main.tf b/modules/tgw/spoke/modules/standard_vpc_attachment/main.tf index 96a28208d..79dda03e7 100644 --- a/modules/tgw/spoke/modules/standard_vpc_attachment/main.tf +++ b/modules/tgw/spoke/modules/standard_vpc_attachment/main.tf @@ -136,7 +136,7 @@ module "standard_vpc_attachment" { subnet_ids = local.own_vpc.private_subnet_ids subnet_route_table_ids = local.own_vpc.private_route_table_ids route_to = null - static_routes = null + static_routes = var.static_routes transit_gateway_vpc_attachment_id = null route_to_cidr_blocks = [for vpc in local.allowed_vpcs : vpc.cidr if !vpc.cross_region] } diff --git a/modules/tgw/spoke/modules/standard_vpc_attachment/outputs.tf b/modules/tgw/spoke/modules/standard_vpc_attachment/outputs.tf index 538a37725..3c21a6725 100644 --- a/modules/tgw/spoke/modules/standard_vpc_attachment/outputs.tf +++ b/modules/tgw/spoke/modules/standard_vpc_attachment/outputs.tf @@ -7,7 +7,7 @@ output "tg_config" { subnet_route_table_ids = null route_to = null route_to_cidr_blocks = null - static_routes = null + static_routes = var.static_routes transit_gateway_vpc_attachment_id = module.standard_vpc_attachment.transit_gateway_vpc_attachment_ids[var.owning_account] } description = "Transit Gateway configuration formatted for handling" diff --git a/modules/tgw/spoke/modules/standard_vpc_attachment/variables.tf b/modules/tgw/spoke/modules/standard_vpc_attachment/variables.tf index 08f294f5d..080fb3544 100644 --- a/modules/tgw/spoke/modules/standard_vpc_attachment/variables.tf +++ b/modules/tgw/spoke/modules/standard_vpc_attachment/variables.tf @@ -50,6 +50,17 @@ variable "connections" { default = [] } +variable "static_routes" { + type = set(object({ + blackhole = bool + destination_cidr_block = string + })) + description = <<-EOT + A list of static routes. + EOT + default = [] +} + variable "expose_eks_sg" { type = bool description = "Set true to allow EKS clusters to accept traffic from source accounts" diff --git a/modules/tgw/spoke/remote-state.tf b/modules/tgw/spoke/remote-state.tf index f6c60563c..41e013679 100644 --- a/modules/tgw/spoke/remote-state.tf +++ b/modules/tgw/spoke/remote-state.tf @@ -15,6 +15,15 @@ module "tgw_hub" { context = module.this.context } +module "vpc" { + source = "cloudposse/stack-config/yaml//modules/remote-state" + version = "1.5.0" + + component = var.own_vpc_component_name + + context = module.this.context +} + module "cross_region_hub_connector" { source = "cloudposse/stack-config/yaml//modules/remote-state" version = "1.5.0" diff --git a/modules/tgw/spoke/variables.tf b/modules/tgw/spoke/variables.tf index a9b66e42f..3f739d692 100644 --- a/modules/tgw/spoke/variables.tf +++ b/modules/tgw/spoke/variables.tf @@ -66,3 +66,26 @@ variable "peered_region" { description = "Set `true` if this region is not the primary region" default = false } + +variable "static_routes" { + type = set(object({ + blackhole = bool + destination_cidr_block = string + })) + description = <<-EOT + A list of static routes. + EOT + default = [] +} + +variable "default_route_enabled" { + type = bool + description = "Enable default routing via transit gateway, requires also nat gateway and instance to be disabled in vpc component. Default is disabled." + default = false +} + +variable "default_route_outgoing_account_name" { + type = string + description = "The account name which is used for outgoing traffic, when using the transit gateway as default route." + default = null +}