diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a6cd369..215c9d8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/antonbabenko/pre-commit-terraform - rev: v1.96.1 + rev: v1.97.0 hooks: - id: terraform_fmt - id: terraform_docs diff --git a/README.md b/README.md index 53900ce..0242eb0 100644 --- a/README.md +++ b/README.md @@ -1,66 +1,123 @@ # AWS Transit Gateway Terraform module -Terraform module which creates Transit Gateway resources on AWS. +Terraform module which creates AWS Transit Gateway resources. -## Usage with VPC module +[![SWUbanner](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner2-direct.svg)](https://github.com/vshymanskyy/StandWithUkraine/blob/main/docs/README.md) + +## Usage ```hcl -module "tgw" { +module "transit_gateway" { source = "terraform-aws-modules/transit-gateway/aws" - version = "~> 2.0" - - name = "my-tgw" - description = "My TGW shared with several other AWS accounts" - enable_auto_accept_shared_attachments = true + name = "example" + description = "Example TGW connecting multiple VPCs" + + # When `true` there is no need for RAM resources if using multiple AWS accounts + auto_accept_shared_attachments = true + + flow_logs = { + tgw = { + log_destination = "arn:aws:s3:::flow-log-bucket" + log_destination_type = "s3" + traffic_type = "ALL" + destination_options = { + file_format = "parquet" + per_hour_partition = true + } + }, + vpc1-attach = { + enable_transit_gateway = false + vpc_attachment_key = "vpc1" + + log_destination = "arn:aws:s3:::flow-log-bucket" + log_destination_type = "s3" + traffic_type = "ALL" + destination_options = { + file_format = "parquet" + per_hour_partition = true + } + }, + vpc2-attach = { + enable_transit_gateway = false + vpc_attachment_key = "vpc2" + + log_destination = "arn:aws:s3:::flow-log-bucket" + log_destination_type = "s3" + traffic_type = "ALL" + destination_options = { + file_format = "parquet" + per_hour_partition = true + } + } + } vpc_attachments = { - vpc = { - vpc_id = module.vpc.vpc_id - subnet_ids = module.vpc.private_subnets - dns_support = true - ipv6_support = true - - tgw_routes = [ - { - destination_cidr_block = "30.0.0.0/16" - }, - { - blackhole = true - destination_cidr_block = "40.0.0.0/20" - } - ] + vpc1 = { + vpc_id = "vpc-1234556abcdef" + security_group_referencing_support = true + subnet_ids = ["sub-abcde012", "sub-bcde012a", "sub-fghi345a"] + ipv6_support = true } - } - ram_allow_external_principals = true - ram_principals = [307990089504] + vpc2 = { + vpc_id = "vpc-98765432d1aad" + security_group_referencing_support = true + subnet_ids = ["sub-334de012", "sub-6vfe012a", "sub-agfi435a"] + } + } tags = { - Purpose = "tgw-complete-example" + Environment = "Development" + Project = "Example" } } -module "vpc" { - source = "terraform-aws-modules/vpc/aws" - version = "~> 3.0" +module "transit_gateway_route_table" { + source = "terraform-aws-modules/transit-gateway/aws//modules/route-table" - name = "my-vpc" + name = "example" + transit_gateway_id = module.transit_gateway.id + + associations = { + vpc1 = { + transit_gateway_attachment_id = module.transit_gateway.vpc_attachments["vpc1"].id + propagate_route_table = true + } + vpc2 = { + transit_gateway_attachment_id = module.transit_gateway.vpc_attachments["vpc2"].id + propagate_route_table = true + } + } - cidr = "10.10.0.0/16" + routes = { + blackhole = { + blackhole = true + destination_cidr_block = "0.0.0.0/0" + } + } - azs = ["eu-west-1a", "eu-west-1b", "eu-west-1c"] - private_subnets = ["10.10.1.0/24", "10.10.2.0/24", "10.10.3.0/24"] + vpc_routes = { + vpc1 = { + destination_cidr_block = "10.0.0.0/16" + route_table_id = "rtb-a73c2ede" + } + vpc2 = { + destination_cidr_block = 10.1.0.0/16" + route_table_id = "rtb-852956e2", + } + } - enable_ipv6 = true - private_subnet_assign_ipv6_address_on_creation = true - private_subnet_ipv6_prefixes = [0, 1, 2] + tags = { + Environment = "Development" + Project = "Example" + } } ``` ## Examples -- [Complete example](https://github.com/terraform-aws-modules/terraform-aws-transit-gateway/tree/master/examples/complete) shows TGW in combination with the [VPC module](https://github.com/terraform-aws-modules/terraform-aws-vpc) and [Resource Access Manager (RAM)](https://aws.amazon.com/ram/). +- [Complete example](https://github.com/terraform-aws-modules/terraform-aws-transit-gateway/tree/master/examples/complete) shows TGW in combination with the [VPC module](https://github.com/terraform-aws-modules/terraform-aws-vpc). - [Multi-account example](https://github.com/terraform-aws-modules/terraform-aws-transit-gateway/tree/master/examples/multi-account) shows TGW resources shared with different AWS accounts (via [Resource Access Manager (RAM)](https://aws.amazon.com/ram/)). @@ -68,14 +125,14 @@ module "vpc" { | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 0.13.1 | -| [aws](#requirement\_aws) | >= 4.4 | +| [terraform](#requirement\_terraform) | >= 1.3 | +| [aws](#requirement\_aws) | >= 5.78 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 4.4 | +| [aws](#provider\_aws) | >= 5.78 | ## Modules @@ -87,70 +144,56 @@ No modules. |------|------| | [aws_ec2_tag.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_tag) | resource | | [aws_ec2_transit_gateway.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_transit_gateway) | resource | -| [aws_ec2_transit_gateway_route.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_transit_gateway_route) | resource | -| [aws_ec2_transit_gateway_route_table.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_transit_gateway_route_table) | resource | -| [aws_ec2_transit_gateway_route_table_association.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_transit_gateway_route_table_association) | resource | -| [aws_ec2_transit_gateway_route_table_propagation.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_transit_gateway_route_table_propagation) | resource | +| [aws_ec2_transit_gateway_peering_attachment.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_transit_gateway_peering_attachment) | resource | +| [aws_ec2_transit_gateway_peering_attachment_accepter.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_transit_gateway_peering_attachment_accepter) | resource | | [aws_ec2_transit_gateway_vpc_attachment.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_transit_gateway_vpc_attachment) | resource | +| [aws_ec2_transit_gateway_vpc_attachment_accepter.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_transit_gateway_vpc_attachment_accepter) | resource | +| [aws_flow_log.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/flow_log) | resource | | [aws_ram_principal_association.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ram_principal_association) | resource | | [aws_ram_resource_association.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ram_resource_association) | resource | | [aws_ram_resource_share.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ram_resource_share) | resource | -| [aws_ram_resource_share_accepter.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ram_resource_share_accepter) | resource | -| [aws_route.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route) | resource | ## Inputs | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| -| [amazon\_side\_asn](#input\_amazon\_side\_asn) | The Autonomous System Number (ASN) for the Amazon side of the gateway. By default the TGW is created with the current default Amazon ASN. | `string` | `null` | no | -| [create\_tgw](#input\_create\_tgw) | Controls if TGW should be created (it affects almost all resources) | `bool` | `true` | no | -| [create\_tgw\_routes](#input\_create\_tgw\_routes) | Controls if TGW Route Table / Routes should be created | `bool` | `true` | no | +| [amazon\_side\_asn](#input\_amazon\_side\_asn) | The Autonomous System Number (ASN) for the Amazon side of the gateway. By default the TGW is created with the current default Amazon ASN | `string` | `null` | no | +| [auto\_accept\_shared\_attachments](#input\_auto\_accept\_shared\_attachments) | Whether resource attachment requests are automatically accepted | `bool` | `true` | no | +| [create](#input\_create) | Controls if resources should be created (it affects almost all resources) | `bool` | `true` | no | +| [create\_flow\_log](#input\_create\_flow\_log) | Whether to create flow log resource(s) | `bool` | `true` | no | +| [default\_route\_table\_association](#input\_default\_route\_table\_association) | Whether resource attachments are automatically associated with the default association route table | `bool` | `false` | no | +| [default\_route\_table\_propagation](#input\_default\_route\_table\_propagation) | Whether resource attachments automatically propagate routes to the default propagation route table | `bool` | `false` | no | | [description](#input\_description) | Description of the EC2 Transit Gateway | `string` | `null` | no | -| [enable\_auto\_accept\_shared\_attachments](#input\_enable\_auto\_accept\_shared\_attachments) | Whether resource attachment requests are automatically accepted | `bool` | `false` | no | -| [enable\_default\_route\_table\_association](#input\_enable\_default\_route\_table\_association) | Whether resource attachments are automatically associated with the default association route table | `bool` | `true` | no | -| [enable\_default\_route\_table\_propagation](#input\_enable\_default\_route\_table\_propagation) | Whether resource attachments automatically propagate routes to the default propagation route table | `bool` | `true` | no | -| [enable\_dns\_support](#input\_enable\_dns\_support) | Should be true to enable DNS support in the TGW | `bool` | `true` | no | -| [enable\_multicast\_support](#input\_enable\_multicast\_support) | Whether multicast support is enabled | `bool` | `false` | no | -| [enable\_sg\_referencing\_support](#input\_enable\_sg\_referencing\_support) | Indicates whether to enable security group referencing support | `bool` | `true` | no | -| [enable\_vpn\_ecmp\_support](#input\_enable\_vpn\_ecmp\_support) | Whether VPN Equal Cost Multipath Protocol support is enabled | `bool` | `true` | no | -| [name](#input\_name) | Name to be used on all the resources as identifier | `string` | `""` | no | -| [ram\_allow\_external\_principals](#input\_ram\_allow\_external\_principals) | Indicates whether principals outside your organization can be associated with a resource share. | `bool` | `false` | no | +| [dns\_support](#input\_dns\_support) | Should be true to enable DNS support in the TGW | `bool` | `true` | no | +| [enable\_ram\_share](#input\_enable\_ram\_share) | Whether to share your transit gateway with other accounts | `bool` | `false` | no | +| [flow\_logs](#input\_flow\_logs) | Flow Logs to create for Transit Gateway or attachments |
map(object({
deliver_cross_account_role = optional(string)
destination_options = optional(object({
file_format = optional(string, "parquet")
hive_compatible_partitions = optional(bool, false)
per_hour_partition = optional(bool, true)
}))
iam_role_arn = optional(string)
log_destination = optional(string)
log_destination_type = optional(string)
log_format = optional(string)
max_aggregation_interval = optional(number, 30)
traffic_type = optional(string, "ALL")
tags = optional(map(string), {})

enable_transit_gateway = optional(bool, true)
# The following can be provided when `enable_transit_gateway` is `false`
vpc_attachment_key = optional(string)
peering_attachment_key = optional(string)
}))
| `{}` | no | +| [multicast\_support](#input\_multicast\_support) | Whether multicast support is enabled | `bool` | `false` | no | +| [name](#input\_name) | Name to be used on all the resources as the identifier | `string` | `""` | no | +| [peering\_attachments](#input\_peering\_attachments) | Map of Transit Gateway peering attachments to create |
map(object({
peer_account_id = string
peer_region = string
peer_transit_gateway_id = string
tags = optional(map(string), {})

accept_peering_attachment = optional(bool, false)
}))
| `{}` | no | +| [ram\_allow\_external\_principals](#input\_ram\_allow\_external\_principals) | Indicates whether principals outside your organization can be associated with a resource share | `bool` | `false` | no | | [ram\_name](#input\_ram\_name) | The name of the resource share of TGW | `string` | `""` | no | -| [ram\_principals](#input\_ram\_principals) | A list of principals to share TGW with. Possible values are an AWS account ID, an AWS Organizations Organization ARN, or an AWS Organizations Organization Unit ARN | `list(string)` | `[]` | no | -| [ram\_resource\_share\_arn](#input\_ram\_resource\_share\_arn) | ARN of RAM resource share | `string` | `""` | no | +| [ram\_principals](#input\_ram\_principals) | A list of principals to share TGW with. Possible values are an AWS account ID, an AWS Organizations Organization ARN, or an AWS Organizations Organization Unit ARN | `set(string)` | `[]` | no | | [ram\_tags](#input\_ram\_tags) | Additional tags for the RAM | `map(string)` | `{}` | no | -| [share\_tgw](#input\_share\_tgw) | Whether to share your transit gateway with other accounts | `bool` | `true` | no | +| [security\_group\_referencing\_support](#input\_security\_group\_referencing\_support) | Whether security group referencing is enabled | `bool` | `false` | no | | [tags](#input\_tags) | A map of tags to add to all resources | `map(string)` | `{}` | no | -| [tgw\_default\_route\_table\_tags](#input\_tgw\_default\_route\_table\_tags) | Additional tags for the Default TGW route table | `map(string)` | `{}` | no | -| [tgw\_route\_table\_tags](#input\_tgw\_route\_table\_tags) | Additional tags for the TGW route table | `map(string)` | `{}` | no | | [tgw\_tags](#input\_tgw\_tags) | Additional tags for the TGW | `map(string)` | `{}` | no | -| [tgw\_vpc\_attachment\_tags](#input\_tgw\_vpc\_attachment\_tags) | Additional tags for VPC attachments | `map(string)` | `{}` | no | | [timeouts](#input\_timeouts) | Create, update, and delete timeout configurations for the transit gateway | `map(string)` | `{}` | no | | [transit\_gateway\_cidr\_blocks](#input\_transit\_gateway\_cidr\_blocks) | One or more IPv4 or IPv6 CIDR blocks for the transit gateway. Must be a size /24 CIDR block or larger for IPv4, or a size /64 CIDR block or larger for IPv6 | `list(string)` | `[]` | no | -| [transit\_gateway\_route\_table\_id](#input\_transit\_gateway\_route\_table\_id) | Identifier of EC2 Transit Gateway Route Table to use with the Target Gateway when reusing it between multiple TGWs | `string` | `null` | no | -| [vpc\_attachments](#input\_vpc\_attachments) | Maps of maps of VPC details to attach to TGW. Type 'any' to disable type validation by Terraform. | `any` | `{}` | no | +| [vpc\_attachments](#input\_vpc\_attachments) | Map of VPC route table attachments to create |
map(object({
appliance_mode_support = optional(bool, false)
dns_support = optional(bool, true)
ipv6_support = optional(bool, false)
security_group_referencing_support = optional(bool, false)
subnet_ids = list(string)
tags = optional(map(string), {})
transit_gateway_default_route_table_association = optional(bool, false)
transit_gateway_default_route_table_propagation = optional(bool, false)
vpc_id = string

accept_peering_attachment = optional(bool, false)
}))
| `{}` | no | +| [vpn\_ecmp\_support](#input\_vpn\_ecmp\_support) | Whether VPN Equal Cost Multipath Protocol support is enabled | `bool` | `true` | no | ## Outputs | Name | Description | |------|-------------| -| [ec2\_transit\_gateway\_arn](#output\_ec2\_transit\_gateway\_arn) | EC2 Transit Gateway Amazon Resource Name (ARN) | -| [ec2\_transit\_gateway\_association\_default\_route\_table\_id](#output\_ec2\_transit\_gateway\_association\_default\_route\_table\_id) | Identifier of the default association route table | -| [ec2\_transit\_gateway\_id](#output\_ec2\_transit\_gateway\_id) | EC2 Transit Gateway identifier | -| [ec2\_transit\_gateway\_owner\_id](#output\_ec2\_transit\_gateway\_owner\_id) | Identifier of the AWS account that owns the EC2 Transit Gateway | -| [ec2\_transit\_gateway\_propagation\_default\_route\_table\_id](#output\_ec2\_transit\_gateway\_propagation\_default\_route\_table\_id) | Identifier of the default propagation route table | -| [ec2\_transit\_gateway\_route\_ids](#output\_ec2\_transit\_gateway\_route\_ids) | List of EC2 Transit Gateway Route Table identifier combined with destination | -| [ec2\_transit\_gateway\_route\_table\_association](#output\_ec2\_transit\_gateway\_route\_table\_association) | Map of EC2 Transit Gateway Route Table Association attributes | -| [ec2\_transit\_gateway\_route\_table\_association\_ids](#output\_ec2\_transit\_gateway\_route\_table\_association\_ids) | List of EC2 Transit Gateway Route Table Association identifiers | -| [ec2\_transit\_gateway\_route\_table\_default\_association\_route\_table](#output\_ec2\_transit\_gateway\_route\_table\_default\_association\_route\_table) | Boolean whether this is the default association route table for the EC2 Transit Gateway | -| [ec2\_transit\_gateway\_route\_table\_default\_propagation\_route\_table](#output\_ec2\_transit\_gateway\_route\_table\_default\_propagation\_route\_table) | Boolean whether this is the default propagation route table for the EC2 Transit Gateway | -| [ec2\_transit\_gateway\_route\_table\_id](#output\_ec2\_transit\_gateway\_route\_table\_id) | EC2 Transit Gateway Route Table identifier | -| [ec2\_transit\_gateway\_route\_table\_propagation](#output\_ec2\_transit\_gateway\_route\_table\_propagation) | Map of EC2 Transit Gateway Route Table Propagation attributes | -| [ec2\_transit\_gateway\_route\_table\_propagation\_ids](#output\_ec2\_transit\_gateway\_route\_table\_propagation\_ids) | List of EC2 Transit Gateway Route Table Propagation identifiers | -| [ec2\_transit\_gateway\_vpc\_attachment](#output\_ec2\_transit\_gateway\_vpc\_attachment) | Map of EC2 Transit Gateway VPC Attachment attributes | -| [ec2\_transit\_gateway\_vpc\_attachment\_ids](#output\_ec2\_transit\_gateway\_vpc\_attachment\_ids) | List of EC2 Transit Gateway VPC Attachment identifiers | -| [ram\_principal\_association\_id](#output\_ram\_principal\_association\_id) | The Amazon Resource Name (ARN) of the Resource Share and the principal, separated by a comma | +| [arn](#output\_arn) | EC2 Transit Gateway Amazon Resource Name (ARN) | +| [association\_default\_route\_table\_id](#output\_association\_default\_route\_table\_id) | Identifier of the default association route table | +| [id](#output\_id) | EC2 Transit Gateway identifier | +| [owner\_id](#output\_owner\_id) | Identifier of the AWS account that owns the EC2 Transit Gateway | +| [peering\_attachments](#output\_peering\_attachments) | Map of TGW peering attachments created | +| [propagation\_default\_route\_table\_id](#output\_propagation\_default\_route\_table\_id) | Identifier of the default propagation route table | | [ram\_resource\_share\_id](#output\_ram\_resource\_share\_id) | The Amazon Resource Name (ARN) of the resource share | +| [vpc\_attachments](#output\_vpc\_attachments) | Map of VPC attachments created | ## Authors diff --git a/UPGRADE-3.0.md b/UPGRADE-3.0.md new file mode 100644 index 0000000..ce73111 --- /dev/null +++ b/UPGRADE-3.0.md @@ -0,0 +1,246 @@ +# Upgrade from v2.x to v3.x + +Please consult the `examples` directory for reference example configurations. If you find a bug, please open an issue with supporting configuration to reproduce. + +## List of backwards incompatible changes + +- Minimum supported version of Terraform AWS provider updated to v5.78 to support the latest resources utilized +- Minimum supported version of Terraform updated to v1.3 +- Route table and routes have been removed from the root module and into a sub-module. This allows for more flexibility in managing routes and route tables (prior implementation was limited to a single route table and routes). Routes are defined via `maps` instead of `lists`, allowing for individual routes to be added/removed anywhere within the configuration without affecting other routes. +- `aws_ram_resource_share_accepter` resource has been removed and should be managed outside of the module as needed. + +## Additional changes + +### Added + +- Added support for security group referencing +- Added support for flow logs on the Transit Gateway itself, as well as any attachments (as specified) +- Added support for Transit Gateway peering attachments + +### Modified + +- `vpc_attachments` type definition changed from `any` to full object definition +- RAM sharing of gateway is now set to `false` by default; users must opt into sharing by setting `enable_ram_share = true` +- `transit_gateway_default_route_table_association` is now set to `false` by default +- `transit_gateway_default_route_table_propagation` is now set to `false` by default + +### Removed + +- `aws_ram_resource_share_accepter` resource has been removed and should be managed outside of the module as needed. + +### Variable and output changes + +1. Removed variables: + + - `tgw_vpc_attachment_tags` + - `create_tgw_routes` + - `transit_gateway_route_table_id` + - `tgw_route_table_tags` + - `ram_resource_share_arn` + +2. Renamed variables: + + - `create_tgw` -> `create` + - `enable_default_route_table_association` -> `default_route_table_association` + - `enable_default_route_table_propagation` -> `default_route_table_propagation` + - `enable_auto_accept_shared_attachments` -> `auto_accept_shared_attachments` + - `enable_vpn_ecmp_support` -> `vpn_ecmp_support` + - `enable_multicast_support` -> `multicast_support` + - `enable_dns_support` -> `dns_support` + - `share_tgw` -> `enable_ram_share` + +3. Added variables: + + - `security_group_referencing_support` + - `peering_attachments` + - `create_flow_log` + - `flow_logs` + +4. Removed outputs: + + - `ec2_transit_gateway_vpc_attachment_ids` + - `ec2_transit_gateway_vpc_attachment` + - `ec2_transit_gateway_route_table_id` + - `ec2_transit_gateway_route_table_default_association_route_table` + - `ec2_transit_gateway_route_table_default_propagation_route_table` + - `ec2_transit_gateway_route_ids` + - `ec2_transit_gateway_route_table_association_ids` + - `ec2_transit_gateway_route_table_association` + - `ec2_transit_gateway_route_table_propagation_ids` + - `ec2_transit_gateway_route_table_propagation` + - `ram_principal_association_id` + +5. Renamed outputs: + + - `ec2_transit_gateway_arn` -> `arn` + - `ec2_transit_gateway_id` -> `id` + - `ec2_transit_gateway_owner_id` -> `owner_id` + - `ec2_transit_gateway_association_default_route_table_id` -> `association_default_route_table` + - `ec2_transit_gateway_propagation_default_route_table_id` -> `propagation_default_route_table` + +6. Added outputs: + + - `vpc_attachments` + - `peering_attachments` + +## Upgrade Migrations + +### Before v2.x Example + +```hcl +module "transit_gateway" { + source = "terraform-aws-modules/transit-gateway/aws" + version = "~> 2.12" + + name = "example" + description = "Example Transit Gateway connecting multiple VPCs" + amazon_side_asn = 64532 + transit_gateway_cidr_blocks = ["10.99.0.0/24"] + + enable_auto_accept_shared_attachments = true + enable_multicast_support = true + + vpc_attachments = { + vpc1 = { + vpc_id = "vpc-1234556abcdef" + subnet_ids = ["subnet-abcde012", "subnet-bcde012a", "subnet-fghi345a"] + ipv6_support = true + + transit_gateway_default_route_table_association = false + transit_gateway_default_route_table_propagation = false + + tgw_routes = [ + { + destination_cidr_block = "30.0.0.0/16" + }, + { + blackhole = true + destination_cidr_block = "0.0.0.0/0" + } + ] + } + + vpc2 = { + vpc_id = module.vpc2.vpc_id + subnet_ids = module.vpc2.private_subnets + + tgw_routes = [ + { + destination_cidr_block = "50.0.0.0/16" + }, + { + blackhole = true + destination_cidr_block = "10.10.10.10/32" + } + ] + } + } + + tags = { + Environment = "Development" + Project = "Example" + } +} +``` + +### After v3.x Example + +```hcl +module "transit_gateway" { + source = "terraform-aws-modules/transit-gateway/aws" + version = "3.0.0" + + name = "example" + description = "Example Transit Gateway connecting multiple VPCs" + amazon_side_asn = 64532 + transit_gateway_cidr_blocks = ["10.99.0.0/24"] + + auto_accept_shared_attachments = true + multicast_support = true + + # Maintain backwards compatibility + security_group_referencing_support = false + default_route_table_association = true + default_route_table_propagation = true + + vpc_attachments = { + vpc1 = { + vpc_id = "vpc-1234556abcdef" + subnet_ids = ["subnet-abcde012", "subnet-bcde012a", "subnet-fghi345a"] + ipv6_support = true + + # Maintain backwards compatibility + security_group_referencing_support = true + } + + vpc2 = { + vpc_id = "vpc-98765432d1aad" + subnet_ids = ["subnet-334de012", "subnet-6vfe012a", "subnet-agfi435a"] + + # Maintain backwards compatibility + security_group_referencing_support = true + transit_gateway_default_route_table_association = true + transit_gateway_default_route_table_propagation = true + } + } + + tags = { + Environment = "Development" + Project = "Example" + } +} + +module "transit_gateway_route_table" { + source = "terraform-aws-modules/transit-gateway/aws//modules/route-table" + + name = "example" + transit_gateway_id = module.transit_gateway.id + + associations = { + vpc1 = { + transit_gateway_attachment_id = module.transit_gateway.vpc_attachments["vpc1"].id + propagate_route_table = true + } + } + + routes = { + blackhole = { + blackhole = true + destination_cidr_block = "0.0.0.0/0" + } + blackhole2 = { + blackhole = true + destination_cidr_block = "10.10.10.10/32" + } + vpc1-thing = { + destination_cidr_block = "30.0.0.0/16" + transit_gateway_attachment_id = module.transit_gateway.vpc_attachments["vpc1"].id + } + vpc2-thing = { + destination_cidr_block = "50.0.0.0/16" + transit_gateway_attachment_id = module.transit_gateway.vpc_attachments["vpc2"].id + } + } + + tags = { + Environment = "Development" + Project = "Example" + } +} +``` + +### State Move Commands + +In conjunction with the changes above, users can elect to move their external capacity provider(s) under this module using the following move command. Command is shown using the values from the example shown above, please update to suit your configuration names: + +```sh +terraform state mv 'module.transit_gateway.aws_ec2_transit_gateway_route_table.this[0]' 'module.transit_gateway_route_table.aws_ec2_transit_gateway_route_table.this[0]' + +terraform state mv 'module.transit_gateway.aws_ec2_transit_gateway_route_table_association.this["vpc1"]' 'module.transit_gateway_route_table.aws_ec2_transit_gateway_route_table_association.this["vpc1"]' +terraform state mv 'module.transit_gateway.aws_ec2_transit_gateway_route_table_propagation.this["vpc1"]' 'module.transit_gateway_route_table.aws_ec2_transit_gateway_route_table_propagation.this["vpc1"]' + +terraform state mv 'module.transit_gateway.aws_ec2_transit_gateway_route.this[0]' 'module.transit_gateway_route_table.aws_ec2_transit_gateway_route.this["vpc1-thing"]' +terraform state mv 'module.transit_gateway.aws_ec2_transit_gateway_route.this[1]' 'module.transit_gateway_route_table.aws_ec2_transit_gateway_route.this["blackhole"]' +terraform state mv 'module.transit_gateway.aws_ec2_transit_gateway_route.this[2]' 'module.transit_gateway_route_table.aws_ec2_transit_gateway_route.this["vpc2-thing"]' +terraform state mv 'module.transit_gateway.aws_ec2_transit_gateway_route.this[3]' 'module.transit_gateway_route_table.aws_ec2_transit_gateway_route.this["blackhole2"]' +``` diff --git a/examples/complete/README.md b/examples/complete/README.md index b4ef9c3..178dbcd 100644 --- a/examples/complete/README.md +++ b/examples/complete/README.md @@ -19,24 +19,35 @@ Note that this example may create resources which cost money. Run `terraform des | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 1.0 | -| [aws](#requirement\_aws) | >= 4.4 | +| [terraform](#requirement\_terraform) | >= 1.3 | +| [aws](#requirement\_aws) | >= 5.78 | +| [random](#requirement\_random) | >= 3.0 | ## Providers -No providers. +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | >= 5.78 | +| [random](#provider\_random) | >= 3.0 | ## Modules | Name | Source | Version | |------|--------|---------| -| [tgw](#module\_tgw) | ../../ | n/a | +| [s3\_bucket](#module\_s3\_bucket) | terraform-aws-modules/s3-bucket/aws | ~> 3.0 | +| [transit\_gateway](#module\_transit\_gateway) | ../../ | n/a | +| [transit\_gateway\_route\_table](#module\_transit\_gateway\_route\_table) | ../../modules/route-table | n/a | | [vpc1](#module\_vpc1) | terraform-aws-modules/vpc/aws | ~> 5.0 | | [vpc2](#module\_vpc2) | terraform-aws-modules/vpc/aws | ~> 5.0 | ## Resources -No resources. +| Name | Type | +|------|------| +| [random_pet.this](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/pet) | resource | +| [aws_availability_zones.available](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/availability_zones) | data source | +| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | +| [aws_iam_policy_document.flow_log_s3](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | ## Inputs @@ -46,21 +57,12 @@ No inputs. | Name | Description | |------|-------------| -| [ec2\_transit\_gateway\_arn](#output\_ec2\_transit\_gateway\_arn) | EC2 Transit Gateway Amazon Resource Name (ARN) | -| [ec2\_transit\_gateway\_association\_default\_route\_table\_id](#output\_ec2\_transit\_gateway\_association\_default\_route\_table\_id) | Identifier of the default association route table | -| [ec2\_transit\_gateway\_id](#output\_ec2\_transit\_gateway\_id) | EC2 Transit Gateway identifier | -| [ec2\_transit\_gateway\_owner\_id](#output\_ec2\_transit\_gateway\_owner\_id) | Identifier of the AWS account that owns the EC2 Transit Gateway | -| [ec2\_transit\_gateway\_propagation\_default\_route\_table\_id](#output\_ec2\_transit\_gateway\_propagation\_default\_route\_table\_id) | Identifier of the default propagation route table | -| [ec2\_transit\_gateway\_route\_ids](#output\_ec2\_transit\_gateway\_route\_ids) | List of EC2 Transit Gateway Route Table identifier combined with destination | -| [ec2\_transit\_gateway\_route\_table\_association](#output\_ec2\_transit\_gateway\_route\_table\_association) | Map of EC2 Transit Gateway Route Table Association attributes | -| [ec2\_transit\_gateway\_route\_table\_association\_ids](#output\_ec2\_transit\_gateway\_route\_table\_association\_ids) | List of EC2 Transit Gateway Route Table Association identifiers | -| [ec2\_transit\_gateway\_route\_table\_default\_association\_route\_table](#output\_ec2\_transit\_gateway\_route\_table\_default\_association\_route\_table) | Boolean whether this is the default association route table for the EC2 Transit Gateway | -| [ec2\_transit\_gateway\_route\_table\_default\_propagation\_route\_table](#output\_ec2\_transit\_gateway\_route\_table\_default\_propagation\_route\_table) | Boolean whether this is the default propagation route table for the EC2 Transit Gateway | -| [ec2\_transit\_gateway\_route\_table\_id](#output\_ec2\_transit\_gateway\_route\_table\_id) | EC2 Transit Gateway Route Table identifier | -| [ec2\_transit\_gateway\_route\_table\_propagation](#output\_ec2\_transit\_gateway\_route\_table\_propagation) | Map of EC2 Transit Gateway Route Table Propagation attributes | -| [ec2\_transit\_gateway\_route\_table\_propagation\_ids](#output\_ec2\_transit\_gateway\_route\_table\_propagation\_ids) | List of EC2 Transit Gateway Route Table Propagation identifiers | -| [ec2\_transit\_gateway\_vpc\_attachment](#output\_ec2\_transit\_gateway\_vpc\_attachment) | Map of EC2 Transit Gateway VPC Attachment attributes | -| [ec2\_transit\_gateway\_vpc\_attachment\_ids](#output\_ec2\_transit\_gateway\_vpc\_attachment\_ids) | List of EC2 Transit Gateway VPC Attachment identifiers | -| [ram\_principal\_association\_id](#output\_ram\_principal\_association\_id) | The Amazon Resource Name (ARN) of the Resource Share and the principal, separated by a comma | +| [arn](#output\_arn) | EC2 Transit Gateway Amazon Resource Name (ARN) | +| [association\_default\_route\_table\_id](#output\_association\_default\_route\_table\_id) | Identifier of the default association route table | +| [id](#output\_id) | EC2 Transit Gateway identifier | +| [owner\_id](#output\_owner\_id) | Identifier of the AWS account that owns the EC2 Transit Gateway | +| [peering\_attachments](#output\_peering\_attachments) | Map of TGW peering attachments created | +| [propagation\_default\_route\_table\_id](#output\_propagation\_default\_route\_table\_id) | Identifier of the default propagation route table | | [ram\_resource\_share\_id](#output\_ram\_resource\_share\_id) | The Amazon Resource Name (ARN) of the resource share | +| [vpc\_attachments](#output\_vpc\_attachments) | Map of VPC attachments created | diff --git a/examples/complete/main.tf b/examples/complete/main.tf index 1f372a8..b42817b 100644 --- a/examples/complete/main.tf +++ b/examples/complete/main.tf @@ -2,14 +2,17 @@ provider "aws" { region = local.region } +data "aws_caller_identity" "current" {} + locals { - name = "ex-tgw-${replace(basename(path.cwd), "_", "-")}" + name = "ex-tgw-${basename(path.cwd)}" region = "eu-west-1" + account_id = data.aws_caller_identity.current.account_id + tags = { Example = local.name - GithubRepo = "terraform-aws-eks" - GithubOrg = "terraform-aws-transit-gateway" + GithubRepo = "terraform-aws-transit-gateway" } } @@ -17,66 +20,103 @@ locals { # Transit Gateway Module ################################################################################ -module "tgw" { +module "transit_gateway" { source = "../../" - name = local.name - description = "My TGW shared with several other AWS accounts" - amazon_side_asn = 64532 - - transit_gateway_cidr_blocks = ["10.99.0.0/24"] - - # When "true" there is no need for RAM resources if using multiple AWS accounts - enable_auto_accept_shared_attachments = true - - # When "true", SG referencing support is enabled at the Transit Gateway level - enable_sg_referencing_support = true - - # When "true", allows service discovery through IGMP - enable_multicast_support = false + name = local.name + description = "Example Transit Gateway connecting multiple VPCs" + amazon_side_asn = 64532 + security_group_referencing_support = true + transit_gateway_cidr_blocks = ["10.99.0.0/24"] + + flow_logs = { + tgw = { + log_destination = module.s3_bucket.s3_bucket_arn + log_destination_type = "s3" + traffic_type = "ALL" + destination_options = { + file_format = "parquet" + per_hour_partition = true + } + }, + vpc1-attach = { + enable_transit_gateway = false + vpc_attachment_key = "vpc1" + + log_destination = module.s3_bucket.s3_bucket_arn + log_destination_type = "s3" + traffic_type = "ALL" + destination_options = { + file_format = "parquet" + per_hour_partition = true + } + }, + vpc2-attach = { + enable_transit_gateway = false + vpc_attachment_key = "vpc2" + + log_destination = module.s3_bucket.s3_bucket_arn + log_destination_type = "s3" + traffic_type = "ALL" + destination_options = { + file_format = "parquet" + per_hour_partition = true + } + } + } vpc_attachments = { vpc1 = { vpc_id = module.vpc1.vpc_id - subnet_ids = module.vpc1.private_subnets security_group_referencing_support = true - dns_support = true + subnet_ids = module.vpc1.private_subnets ipv6_support = true + } - transit_gateway_default_route_table_association = false - transit_gateway_default_route_table_propagation = false - - tgw_routes = [ - { - destination_cidr_block = "30.0.0.0/16" - }, - { - blackhole = true - destination_cidr_block = "0.0.0.0/0" - } - ] - }, vpc2 = { - vpc_id = module.vpc2.vpc_id - subnet_ids = module.vpc2.private_subnets - - tgw_routes = [ - { - destination_cidr_block = "50.0.0.0/16" - }, - { - blackhole = true - destination_cidr_block = "10.10.10.10/32" - } - ] - tags = { - Name = "${local.name}-vpc2" - } - }, + vpc_id = module.vpc2.vpc_id + security_group_referencing_support = true + subnet_ids = module.vpc2.private_subnets + } } - ram_allow_external_principals = true - ram_principals = [307990089504] + tags = local.tags +} + +module "transit_gateway_route_table" { + source = "../../modules/route-table" + + name = local.name + transit_gateway_id = module.transit_gateway.id + + associations = { + vpc1 = { + transit_gateway_attachment_id = module.transit_gateway.vpc_attachments["vpc1"].id + propagate_route_table = true + } + vpc2 = { + transit_gateway_attachment_id = module.transit_gateway.vpc_attachments["vpc2"].id + propagate_route_table = true + } + } + + routes = { + blackhole = { + blackhole = true + destination_cidr_block = "0.0.0.0/0" + } + } + + vpc_routes = { + vpc1 = { + destination_cidr_block = module.vpc2.vpc_cidr_block + route_table_id = element(module.vpc1.private_route_table_ids, 0) + } + vpc2 = { + destination_cidr_block = module.vpc1.vpc_cidr_block + route_table_id = element(module.vpc2.private_route_table_ids, 0) + } + } tags = local.tags } @@ -85,15 +125,29 @@ module "tgw" { # Supporting resources ################################################################################ +locals { + vpc1_cidr = "10.0.0.0/16" + vpc2_cidr = "10.20.0.0/16" + azs = slice(data.aws_availability_zones.available.names, 0, 3) +} + +data "aws_availability_zones" "available" { + # Exclude local zones + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} + module "vpc1" { source = "terraform-aws-modules/vpc/aws" version = "~> 5.0" name = "${local.name}-vpc1" - cidr = "10.10.0.0/16" + cidr = local.vpc1_cidr - azs = ["${local.region}a", "${local.region}b", "${local.region}c"] - private_subnets = ["10.10.1.0/24", "10.10.2.0/24", "10.10.3.0/24"] + azs = local.azs + private_subnets = [for k, v in local.azs : cidrsubnet(local.vpc1_cidr, 4, k)] enable_ipv6 = true private_subnet_assign_ipv6_address_on_creation = true @@ -107,12 +161,84 @@ module "vpc2" { version = "~> 5.0" name = "${local.name}-vpc2" - cidr = "10.20.0.0/16" + cidr = local.vpc2_cidr + + azs = local.azs + private_subnets = [for k, v in local.azs : cidrsubnet(local.vpc2_cidr, 4, k)] + + tags = local.tags +} + +resource "random_pet" "this" { + length = 2 +} - azs = ["${local.region}a", "${local.region}b", "${local.region}c"] - private_subnets = ["10.20.1.0/24", "10.20.2.0/24", "10.20.3.0/24"] +module "s3_bucket" { + source = "terraform-aws-modules/s3-bucket/aws" + version = "~> 3.0" - enable_ipv6 = false + bucket = "${local.name}-${random_pet.this.id}" + policy = data.aws_iam_policy_document.flow_log_s3.json + force_destroy = true tags = local.tags } + +data "aws_iam_policy_document" "flow_log_s3" { + statement { + sid = "AWSLogDeliveryWrite" + + principals { + type = "Service" + identifiers = ["delivery.logs.amazonaws.com"] + } + + actions = ["s3:PutObject"] + resources = ["arn:aws:s3:::${local.name}-${random_pet.this.id}/*"] + + condition { + test = "StringEquals" + variable = "s3:x-amz-acl" + values = ["bucket-owner-full-control"] + } + + condition { + test = "StringEquals" + variable = "aws:SourceAccount" + values = [local.account_id] + } + + condition { + test = "ArnLike" + variable = "aws:SourceArn" + values = ["arn:aws:logs:${local.region}:${local.account_id}:*"] + } + } + + statement { + sid = "AWSLogDeliveryAclCheck" + + principals { + type = "Service" + identifiers = ["delivery.logs.amazonaws.com"] + } + + actions = [ + "s3:Get*", + "s3:List*", + ] + resources = ["arn:aws:s3:::${local.name}-${random_pet.this.id}"] + + condition { + test = "StringEquals" + variable = "aws:SourceAccount" + values = [local.account_id] + } + + condition { + test = "ArnLike" + variable = "aws:SourceArn" + values = ["arn:aws:logs:${local.region}:${local.account_id}:*"] + } + } +} diff --git a/examples/complete/outputs.tf b/examples/complete/outputs.tf index b9a0a40..ddadb24 100644 --- a/examples/complete/outputs.tf +++ b/examples/complete/outputs.tf @@ -2,99 +2,54 @@ # Transit Gateway ################################################################################ -output "ec2_transit_gateway_arn" { +output "arn" { description = "EC2 Transit Gateway Amazon Resource Name (ARN)" - value = module.tgw.ec2_transit_gateway_arn + value = module.transit_gateway.arn } -output "ec2_transit_gateway_id" { +output "id" { description = "EC2 Transit Gateway identifier" - value = module.tgw.ec2_transit_gateway_id + value = module.transit_gateway.id } -output "ec2_transit_gateway_owner_id" { +output "owner_id" { description = "Identifier of the AWS account that owns the EC2 Transit Gateway" - value = module.tgw.ec2_transit_gateway_owner_id + value = module.transit_gateway.owner_id } -output "ec2_transit_gateway_association_default_route_table_id" { +output "association_default_route_table_id" { description = "Identifier of the default association route table" - value = module.tgw.ec2_transit_gateway_association_default_route_table_id + value = module.transit_gateway.association_default_route_table_id } -output "ec2_transit_gateway_propagation_default_route_table_id" { +output "propagation_default_route_table_id" { description = "Identifier of the default propagation route table" - value = module.tgw.ec2_transit_gateway_propagation_default_route_table_id + value = module.transit_gateway.propagation_default_route_table_id } ################################################################################ -# VPC Attachment +# Resource Access Manager ################################################################################ -output "ec2_transit_gateway_vpc_attachment_ids" { - description = "List of EC2 Transit Gateway VPC Attachment identifiers" - value = module.tgw.ec2_transit_gateway_vpc_attachment_ids -} - -output "ec2_transit_gateway_vpc_attachment" { - description = "Map of EC2 Transit Gateway VPC Attachment attributes" - value = module.tgw.ec2_transit_gateway_vpc_attachment +output "ram_resource_share_id" { + description = "The Amazon Resource Name (ARN) of the resource share" + value = module.transit_gateway.ram_resource_share_id } ################################################################################ -# Route Table / Routes +# VPC Attachment ################################################################################ -output "ec2_transit_gateway_route_table_id" { - description = "EC2 Transit Gateway Route Table identifier" - value = module.tgw.ec2_transit_gateway_route_table_id -} - -output "ec2_transit_gateway_route_table_default_association_route_table" { - description = "Boolean whether this is the default association route table for the EC2 Transit Gateway" - value = module.tgw.ec2_transit_gateway_route_table_default_association_route_table -} - -output "ec2_transit_gateway_route_table_default_propagation_route_table" { - description = "Boolean whether this is the default propagation route table for the EC2 Transit Gateway" - value = module.tgw.ec2_transit_gateway_route_table_default_propagation_route_table -} - -output "ec2_transit_gateway_route_ids" { - description = "List of EC2 Transit Gateway Route Table identifier combined with destination" - value = module.tgw.ec2_transit_gateway_route_ids -} - -output "ec2_transit_gateway_route_table_association_ids" { - description = "List of EC2 Transit Gateway Route Table Association identifiers" - value = module.tgw.ec2_transit_gateway_route_table_association_ids -} - -output "ec2_transit_gateway_route_table_association" { - description = "Map of EC2 Transit Gateway Route Table Association attributes" - value = module.tgw.ec2_transit_gateway_route_table_association -} - -output "ec2_transit_gateway_route_table_propagation_ids" { - description = "List of EC2 Transit Gateway Route Table Propagation identifiers" - value = module.tgw.ec2_transit_gateway_route_table_propagation_ids -} - -output "ec2_transit_gateway_route_table_propagation" { - description = "Map of EC2 Transit Gateway Route Table Propagation attributes" - value = module.tgw.ec2_transit_gateway_route_table_propagation +output "vpc_attachments" { + description = "Map of VPC attachments created" + value = module.transit_gateway.vpc_attachments } ################################################################################ -# Resource Access Manager +# TGW Peering Attachment ################################################################################ -output "ram_resource_share_id" { - description = "The Amazon Resource Name (ARN) of the resource share" - value = module.tgw.ram_resource_share_id -} - -output "ram_principal_association_id" { - description = "The Amazon Resource Name (ARN) of the Resource Share and the principal, separated by a comma" - value = module.tgw.ram_principal_association_id +output "peering_attachments" { + description = "Map of TGW peering attachments created" + value = module.transit_gateway.peering_attachments } diff --git a/examples/complete/versions.tf b/examples/complete/versions.tf index 46b7087..880294f 100644 --- a/examples/complete/versions.tf +++ b/examples/complete/versions.tf @@ -1,10 +1,14 @@ terraform { - required_version = ">= 1.0" + required_version = ">= 1.3" required_providers { aws = { source = "hashicorp/aws" - version = ">= 4.4" + version = ">= 5.78" + } + random = { + source = "hashicorp/random" + version = ">= 3.0" } } } diff --git a/examples/multi-account/README.md b/examples/multi-account/README.md index d3726ee..7b4c68a 100644 --- a/examples/multi-account/README.md +++ b/examples/multi-account/README.md @@ -19,25 +19,35 @@ Note that this example may create resources which cost money. Run `terraform des | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 1.0 | -| [aws](#requirement\_aws) | >= 4.4 | +| [terraform](#requirement\_terraform) | >= 1.3 | +| [aws](#requirement\_aws) | >= 5.78 | +| [random](#requirement\_random) | >= 3.0 | ## Providers -No providers. +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | >= 5.78 | +| [random](#provider\_random) | >= 3.0 | ## Modules | Name | Source | Version | |------|--------|---------| -| [tgw](#module\_tgw) | ../../ | n/a | -| [tgw\_peer](#module\_tgw\_peer) | ../../ | n/a | +| [s3\_bucket](#module\_s3\_bucket) | terraform-aws-modules/s3-bucket/aws | ~> 3.0 | +| [transit\_gateway](#module\_transit\_gateway) | ../../ | n/a | +| [transit\_gateway\_peer](#module\_transit\_gateway\_peer) | ../../ | n/a | | [vpc1](#module\_vpc1) | terraform-aws-modules/vpc/aws | ~> 5.0 | | [vpc2](#module\_vpc2) | terraform-aws-modules/vpc/aws | ~> 5.0 | ## Resources -No resources. +| Name | Type | +|------|------| +| [random_pet.this](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/pet) | resource | +| [aws_availability_zones.available](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/availability_zones) | data source | +| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | +| [aws_iam_policy_document.flow_log_s3](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | ## Inputs @@ -47,21 +57,12 @@ No inputs. | Name | Description | |------|-------------| -| [ec2\_transit\_gateway\_arn](#output\_ec2\_transit\_gateway\_arn) | EC2 Transit Gateway Amazon Resource Name (ARN) | -| [ec2\_transit\_gateway\_association\_default\_route\_table\_id](#output\_ec2\_transit\_gateway\_association\_default\_route\_table\_id) | Identifier of the default association route table | -| [ec2\_transit\_gateway\_id](#output\_ec2\_transit\_gateway\_id) | EC2 Transit Gateway identifier | -| [ec2\_transit\_gateway\_owner\_id](#output\_ec2\_transit\_gateway\_owner\_id) | Identifier of the AWS account that owns the EC2 Transit Gateway | -| [ec2\_transit\_gateway\_propagation\_default\_route\_table\_id](#output\_ec2\_transit\_gateway\_propagation\_default\_route\_table\_id) | Identifier of the default propagation route table | -| [ec2\_transit\_gateway\_route\_ids](#output\_ec2\_transit\_gateway\_route\_ids) | List of EC2 Transit Gateway Route Table identifier combined with destination | -| [ec2\_transit\_gateway\_route\_table\_association](#output\_ec2\_transit\_gateway\_route\_table\_association) | Map of EC2 Transit Gateway Route Table Association attributes | -| [ec2\_transit\_gateway\_route\_table\_association\_ids](#output\_ec2\_transit\_gateway\_route\_table\_association\_ids) | List of EC2 Transit Gateway Route Table Association identifiers | -| [ec2\_transit\_gateway\_route\_table\_default\_association\_route\_table](#output\_ec2\_transit\_gateway\_route\_table\_default\_association\_route\_table) | Boolean whether this is the default association route table for the EC2 Transit Gateway | -| [ec2\_transit\_gateway\_route\_table\_default\_propagation\_route\_table](#output\_ec2\_transit\_gateway\_route\_table\_default\_propagation\_route\_table) | Boolean whether this is the default propagation route table for the EC2 Transit Gateway | -| [ec2\_transit\_gateway\_route\_table\_id](#output\_ec2\_transit\_gateway\_route\_table\_id) | EC2 Transit Gateway Route Table identifier | -| [ec2\_transit\_gateway\_route\_table\_propagation](#output\_ec2\_transit\_gateway\_route\_table\_propagation) | Map of EC2 Transit Gateway Route Table Propagation attributes | -| [ec2\_transit\_gateway\_route\_table\_propagation\_ids](#output\_ec2\_transit\_gateway\_route\_table\_propagation\_ids) | List of EC2 Transit Gateway Route Table Propagation identifiers | -| [ec2\_transit\_gateway\_vpc\_attachment](#output\_ec2\_transit\_gateway\_vpc\_attachment) | Map of EC2 Transit Gateway VPC Attachment attributes | -| [ec2\_transit\_gateway\_vpc\_attachment\_ids](#output\_ec2\_transit\_gateway\_vpc\_attachment\_ids) | List of EC2 Transit Gateway VPC Attachment identifiers | -| [ram\_principal\_association\_id](#output\_ram\_principal\_association\_id) | The Amazon Resource Name (ARN) of the Resource Share and the principal, separated by a comma | +| [arn](#output\_arn) | EC2 Transit Gateway Amazon Resource Name (ARN) | +| [association\_default\_route\_table\_id](#output\_association\_default\_route\_table\_id) | Identifier of the default association route table | +| [id](#output\_id) | EC2 Transit Gateway identifier | +| [owner\_id](#output\_owner\_id) | Identifier of the AWS account that owns the EC2 Transit Gateway | +| [peering\_attachments](#output\_peering\_attachments) | Map of TGW peering attachments created | +| [propagation\_default\_route\_table\_id](#output\_propagation\_default\_route\_table\_id) | Identifier of the default propagation route table | | [ram\_resource\_share\_id](#output\_ram\_resource\_share\_id) | The Amazon Resource Name (ARN) of the resource share | +| [vpc\_attachments](#output\_vpc\_attachments) | Map of VPC attachments created | diff --git a/examples/multi-account/main.tf b/examples/multi-account/main.tf index 56e0b70..537ef36 100644 --- a/examples/multi-account/main.tf +++ b/examples/multi-account/main.tf @@ -8,10 +8,14 @@ provider "aws" { alias = "peer" } +data "aws_caller_identity" "current" {} + locals { name = "ex-tgw-${replace(basename(path.cwd), "_", "-")}" region = "eu-west-1" + account_id = data.aws_caller_identity.current.account_id + tags = { Example = local.name GithubRepo = "terraform-aws-eks" @@ -23,26 +27,19 @@ locals { # Transit Gateway Module ################################################################################ -module "tgw" { +module "transit_gateway" { source = "../../" name = local.name - description = "My TGW shared with several other AWS accounts" + description = "Example Transit Gateway shared with several other AWS accounts" amazon_side_asn = 64532 - # When "true" there is no need for RAM resources if using multiple AWS accounts - enable_auto_accept_shared_attachments = true - vpc_attachments = { vpc1 = { vpc_id = module.vpc1.vpc_id subnet_ids = module.vpc1.private_subnets - dns_support = true ipv6_support = true - transit_gateway_default_route_table_association = false - transit_gateway_default_route_table_propagation = false - tgw_routes = [ { destination_cidr_block = "30.0.0.0/16" @@ -69,14 +66,10 @@ module "tgw" { }, } - ram_allow_external_principals = true - ram_principals = [307990089504] - tags = local.tags } -module "tgw_peer" { - # This is optional and connects to another account. Meaning you need to be authenticated with 2 separate AWS Accounts +module "transit_gateway_peer" { source = "../../" providers = { @@ -87,23 +80,13 @@ module "tgw_peer" { description = "My TGW shared with several other AWS accounts" amazon_side_asn = 64532 - create_tgw = false - share_tgw = true - ram_resource_share_arn = module.tgw.ram_resource_share_id - # When "true" there is no need for RAM resources if using multiple AWS accounts - enable_auto_accept_shared_attachments = true - vpc_attachments = { vpc1 = { - tgw_id = module.tgw.ec2_transit_gateway_id + tgw_id = module.transit_gateway.id vpc_id = module.vpc1.vpc_id subnet_ids = module.vpc1.private_subnets - dns_support = true ipv6_support = true - transit_gateway_default_route_table_association = false - transit_gateway_default_route_table_propagation = false - vpc_route_table_ids = module.vpc1.private_route_table_ids tgw_destination_cidr = "0.0.0.0/0" @@ -119,9 +102,6 @@ module "tgw_peer" { }, } - ram_allow_external_principals = true - ram_principals = [307990089504] - tags = local.tags } @@ -129,15 +109,29 @@ module "tgw_peer" { # Supporting resources ################################################################################ +locals { + vpc1_cidr = "10.0.0.0/16" + vpc2_cidr = "10.20.0.0/16" + azs = slice(data.aws_availability_zones.available.names, 0, 3) +} + +data "aws_availability_zones" "available" { + # Exclude local zones + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} + module "vpc1" { source = "terraform-aws-modules/vpc/aws" version = "~> 5.0" name = "${local.name}-vpc1" - cidr = "10.10.0.0/16" + cidr = local.vpc1_cidr - azs = ["${local.region}a", "${local.region}b", "${local.region}c"] - private_subnets = ["10.10.1.0/24", "10.10.2.0/24", "10.10.3.0/24"] + azs = local.azs + private_subnets = [for k, v in local.azs : cidrsubnet(local.vpc1_cidr, 4, k)] enable_ipv6 = true private_subnet_assign_ipv6_address_on_creation = true @@ -146,22 +140,89 @@ module "vpc1" { tags = local.tags } - module "vpc2" { source = "terraform-aws-modules/vpc/aws" version = "~> 5.0" - providers = { - aws = aws.peer - } - name = "${local.name}-vpc2" - cidr = "10.20.0.0/16" + cidr = local.vpc2_cidr - azs = ["${local.region}a", "${local.region}b", "${local.region}c"] - private_subnets = ["10.20.1.0/24", "10.20.2.0/24", "10.20.3.0/24"] + azs = local.azs + private_subnets = [for k, v in local.azs : cidrsubnet(local.vpc2_cidr, 4, k)] - enable_ipv6 = false + tags = local.tags +} + +resource "random_pet" "this" { + length = 2 +} + +module "s3_bucket" { + source = "terraform-aws-modules/s3-bucket/aws" + version = "~> 3.0" + + bucket = "${local.name}-${random_pet.this.id}" + policy = data.aws_iam_policy_document.flow_log_s3.json + force_destroy = true tags = local.tags } + +data "aws_iam_policy_document" "flow_log_s3" { + statement { + sid = "AWSLogDeliveryWrite" + + principals { + type = "Service" + identifiers = ["delivery.logs.amazonaws.com"] + } + + actions = ["s3:PutObject"] + resources = ["arn:aws:s3:::${local.name}-${random_pet.this.id}/*"] + + condition { + test = "StringEquals" + variable = "s3:x-amz-acl" + values = ["bucket-owner-full-control"] + } + + condition { + test = "StringEquals" + variable = "aws:SourceAccount" + values = [local.account_id] + } + + condition { + test = "ArnLike" + variable = "aws:SourceArn" + values = ["arn:aws:logs:${local.region}:${local.account_id}:*"] + } + } + + statement { + sid = "AWSLogDeliveryAclCheck" + + principals { + type = "Service" + identifiers = ["delivery.logs.amazonaws.com"] + } + + actions = [ + "s3:Get*", + "s3:List*", + ] + resources = ["arn:aws:s3:::${local.name}-${random_pet.this.id}"] + + condition { + test = "StringEquals" + variable = "aws:SourceAccount" + values = [local.account_id] + } + + condition { + test = "ArnLike" + variable = "aws:SourceArn" + values = ["arn:aws:logs:${local.region}:${local.account_id}:*"] + } + } +} diff --git a/examples/multi-account/outputs.tf b/examples/multi-account/outputs.tf index b9a0a40..ddadb24 100644 --- a/examples/multi-account/outputs.tf +++ b/examples/multi-account/outputs.tf @@ -2,99 +2,54 @@ # Transit Gateway ################################################################################ -output "ec2_transit_gateway_arn" { +output "arn" { description = "EC2 Transit Gateway Amazon Resource Name (ARN)" - value = module.tgw.ec2_transit_gateway_arn + value = module.transit_gateway.arn } -output "ec2_transit_gateway_id" { +output "id" { description = "EC2 Transit Gateway identifier" - value = module.tgw.ec2_transit_gateway_id + value = module.transit_gateway.id } -output "ec2_transit_gateway_owner_id" { +output "owner_id" { description = "Identifier of the AWS account that owns the EC2 Transit Gateway" - value = module.tgw.ec2_transit_gateway_owner_id + value = module.transit_gateway.owner_id } -output "ec2_transit_gateway_association_default_route_table_id" { +output "association_default_route_table_id" { description = "Identifier of the default association route table" - value = module.tgw.ec2_transit_gateway_association_default_route_table_id + value = module.transit_gateway.association_default_route_table_id } -output "ec2_transit_gateway_propagation_default_route_table_id" { +output "propagation_default_route_table_id" { description = "Identifier of the default propagation route table" - value = module.tgw.ec2_transit_gateway_propagation_default_route_table_id + value = module.transit_gateway.propagation_default_route_table_id } ################################################################################ -# VPC Attachment +# Resource Access Manager ################################################################################ -output "ec2_transit_gateway_vpc_attachment_ids" { - description = "List of EC2 Transit Gateway VPC Attachment identifiers" - value = module.tgw.ec2_transit_gateway_vpc_attachment_ids -} - -output "ec2_transit_gateway_vpc_attachment" { - description = "Map of EC2 Transit Gateway VPC Attachment attributes" - value = module.tgw.ec2_transit_gateway_vpc_attachment +output "ram_resource_share_id" { + description = "The Amazon Resource Name (ARN) of the resource share" + value = module.transit_gateway.ram_resource_share_id } ################################################################################ -# Route Table / Routes +# VPC Attachment ################################################################################ -output "ec2_transit_gateway_route_table_id" { - description = "EC2 Transit Gateway Route Table identifier" - value = module.tgw.ec2_transit_gateway_route_table_id -} - -output "ec2_transit_gateway_route_table_default_association_route_table" { - description = "Boolean whether this is the default association route table for the EC2 Transit Gateway" - value = module.tgw.ec2_transit_gateway_route_table_default_association_route_table -} - -output "ec2_transit_gateway_route_table_default_propagation_route_table" { - description = "Boolean whether this is the default propagation route table for the EC2 Transit Gateway" - value = module.tgw.ec2_transit_gateway_route_table_default_propagation_route_table -} - -output "ec2_transit_gateway_route_ids" { - description = "List of EC2 Transit Gateway Route Table identifier combined with destination" - value = module.tgw.ec2_transit_gateway_route_ids -} - -output "ec2_transit_gateway_route_table_association_ids" { - description = "List of EC2 Transit Gateway Route Table Association identifiers" - value = module.tgw.ec2_transit_gateway_route_table_association_ids -} - -output "ec2_transit_gateway_route_table_association" { - description = "Map of EC2 Transit Gateway Route Table Association attributes" - value = module.tgw.ec2_transit_gateway_route_table_association -} - -output "ec2_transit_gateway_route_table_propagation_ids" { - description = "List of EC2 Transit Gateway Route Table Propagation identifiers" - value = module.tgw.ec2_transit_gateway_route_table_propagation_ids -} - -output "ec2_transit_gateway_route_table_propagation" { - description = "Map of EC2 Transit Gateway Route Table Propagation attributes" - value = module.tgw.ec2_transit_gateway_route_table_propagation +output "vpc_attachments" { + description = "Map of VPC attachments created" + value = module.transit_gateway.vpc_attachments } ################################################################################ -# Resource Access Manager +# TGW Peering Attachment ################################################################################ -output "ram_resource_share_id" { - description = "The Amazon Resource Name (ARN) of the resource share" - value = module.tgw.ram_resource_share_id -} - -output "ram_principal_association_id" { - description = "The Amazon Resource Name (ARN) of the Resource Share and the principal, separated by a comma" - value = module.tgw.ram_principal_association_id +output "peering_attachments" { + description = "Map of TGW peering attachments created" + value = module.transit_gateway.peering_attachments } diff --git a/examples/multi-account/versions.tf b/examples/multi-account/versions.tf index 46b7087..880294f 100644 --- a/examples/multi-account/versions.tf +++ b/examples/multi-account/versions.tf @@ -1,10 +1,14 @@ terraform { - required_version = ">= 1.0" + required_version = ">= 1.3" required_providers { aws = { source = "hashicorp/aws" - version = ">= 4.4" + version = ">= 5.78" + } + random = { + source = "hashicorp/random" + version = ">= 3.0" } } } diff --git a/main.tf b/main.tf index 01c584b..f243114 100644 --- a/main.tf +++ b/main.tf @@ -1,43 +1,28 @@ -locals { - # List of maps with key and route values - vpc_attachments_with_routes = chunklist(flatten([ - for k, v in var.vpc_attachments : setproduct([{ key = k }], v.tgw_routes) if var.create_tgw && can(v.tgw_routes) - ]), 2) +################################################################################ +# Transit Gateway +################################################################################ - tgw_default_route_table_tags_merged = merge( +locals { + tgw_tags = merge( var.tags, { Name = var.name }, - var.tgw_default_route_table_tags, + var.tgw_tags, ) - - vpc_route_table_destination_cidr = flatten([ - for k, v in var.vpc_attachments : [ - for rtb_id in try(v.vpc_route_table_ids, []) : { - rtb_id = rtb_id - cidr = v.tgw_destination_cidr - tgw_id = var.create_tgw ? aws_ec2_transit_gateway.this[0].id : v.tgw_id - } - ] - ]) } -################################################################################ -# Transit Gateway -################################################################################ - resource "aws_ec2_transit_gateway" "this" { - count = var.create_tgw ? 1 : 0 + count = var.create ? 1 : 0 - description = coalesce(var.description, var.name) amazon_side_asn = var.amazon_side_asn - default_route_table_association = var.enable_default_route_table_association ? "enable" : "disable" - default_route_table_propagation = var.enable_default_route_table_propagation ? "enable" : "disable" - auto_accept_shared_attachments = var.enable_auto_accept_shared_attachments ? "enable" : "disable" - multicast_support = var.enable_multicast_support ? "enable" : "disable" - vpn_ecmp_support = var.enable_vpn_ecmp_support ? "enable" : "disable" - dns_support = var.enable_dns_support ? "enable" : "disable" + auto_accept_shared_attachments = var.auto_accept_shared_attachments ? "enable" : "disable" + default_route_table_association = var.default_route_table_association ? "enable" : "disable" + default_route_table_propagation = var.default_route_table_propagation ? "enable" : "disable" + description = var.description + dns_support = var.dns_support ? "enable" : "disable" + multicast_support = var.multicast_support ? "enable" : "disable" + security_group_referencing_support = var.security_group_referencing_support ? "enable" : "disable" transit_gateway_cidr_blocks = var.transit_gateway_cidr_blocks - security_group_referencing_support = var.enable_sg_referencing_support ? "enable" : "disable" + vpn_ecmp_support = var.vpn_ecmp_support ? "enable" : "disable" timeouts { create = try(var.timeouts.create, null) @@ -45,15 +30,11 @@ resource "aws_ec2_transit_gateway" "this" { delete = try(var.timeouts.delete, null) } - tags = merge( - var.tags, - { Name = var.name }, - var.tgw_tags, - ) + tags = local.tgw_tags } resource "aws_ec2_tag" "this" { - for_each = { for k, v in local.tgw_default_route_table_tags_merged : k => v if var.create_tgw && var.enable_default_route_table_association } + for_each = { for k, v in local.tgw_tags : k => v if var.create && var.default_route_table_association } resource_id = aws_ec2_transit_gateway.this[0].association_default_route_table_id key = each.key @@ -65,118 +46,138 @@ resource "aws_ec2_tag" "this" { ################################################################################ resource "aws_ec2_transit_gateway_vpc_attachment" "this" { - for_each = var.vpc_attachments - - transit_gateway_id = var.create_tgw ? aws_ec2_transit_gateway.this[0].id : each.value.tgw_id - vpc_id = each.value.vpc_id - subnet_ids = each.value.subnet_ids - - dns_support = try(each.value.dns_support, true) ? "enable" : "disable" - ipv6_support = try(each.value.ipv6_support, false) ? "enable" : "disable" - appliance_mode_support = try(each.value.appliance_mode_support, false) ? "enable" : "disable" - security_group_referencing_support = try(each.value.security_group_referencing_support, false) ? "enable" : "disable" - transit_gateway_default_route_table_association = try(each.value.transit_gateway_default_route_table_association, true) - transit_gateway_default_route_table_propagation = try(each.value.transit_gateway_default_route_table_propagation, true) + for_each = { for k, v in var.vpc_attachments : k => v if var.create } + + appliance_mode_support = each.value.appliance_mode_support ? "enable" : "disable" + dns_support = each.value.dns_support ? "enable" : "disable" + ipv6_support = each.value.ipv6_support ? "enable" : "disable" + security_group_referencing_support = each.value.security_group_referencing_support ? "enable" : "disable" + subnet_ids = each.value.subnet_ids + 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 + transit_gateway_id = aws_ec2_transit_gateway.this[0].id + vpc_id = each.value.vpc_id tags = merge( var.tags, - { Name = var.name }, - var.tgw_vpc_attachment_tags, - try(each.value.tags, {}), + { Name = "${var.name}-${each.key}" }, + each.value.tags, ) } -################################################################################ -# Route Table / Routes -################################################################################ - -resource "aws_ec2_transit_gateway_route_table" "this" { - count = var.create_tgw && var.create_tgw_routes ? 1 : 0 +resource "aws_ec2_transit_gateway_vpc_attachment_accepter" "this" { + for_each = { for k, v in var.vpc_attachments : k => v if var.create && v.accept_peering_attachment } - transit_gateway_id = aws_ec2_transit_gateway.this[0].id + transit_gateway_attachment_id = aws_ec2_transit_gateway_vpc_attachment.this[0] + 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 tags = merge( var.tags, - { Name = var.name }, - var.tgw_route_table_tags, + each.value.tags, ) } -resource "aws_ec2_transit_gateway_route" "this" { - count = var.create_tgw_routes ? length(local.vpc_attachments_with_routes) : 0 - - destination_cidr_block = local.vpc_attachments_with_routes[count.index][1].destination_cidr_block - blackhole = try(local.vpc_attachments_with_routes[count.index][1].blackhole, null) +################################################################################ +# TGW Peering Attachment +################################################################################ - transit_gateway_route_table_id = var.create_tgw ? aws_ec2_transit_gateway_route_table.this[0].id : var.transit_gateway_route_table_id - transit_gateway_attachment_id = tobool(try(local.vpc_attachments_with_routes[count.index][1].blackhole, false)) == false ? aws_ec2_transit_gateway_vpc_attachment.this[local.vpc_attachments_with_routes[count.index][0].key].id : null -} +resource "aws_ec2_transit_gateway_peering_attachment" "this" { + for_each = { for k, v in var.peering_attachments : k => v if var.create } -resource "aws_route" "this" { - for_each = { for x in local.vpc_route_table_destination_cidr : x.rtb_id => { - cidr = x.cidr, - tgw_id = x.tgw_id - } } + peer_account_id = each.value.peer_account_id + peer_region = each.value.peer_region + peer_transit_gateway_id = each.value.peer_transit_gateway_id + transit_gateway_id = aws_ec2_transit_gateway.this[0].id - route_table_id = each.key - destination_cidr_block = try(each.value.ipv6_support, false) ? null : each.value["cidr"] - destination_ipv6_cidr_block = try(each.value.ipv6_support, false) ? each.value["cidr"] : null - transit_gateway_id = each.value["tgw_id"] + tags = merge( + var.tags, + { Name = "${var.name}-${each.key}" }, + each.value.tags, + ) } -resource "aws_ec2_transit_gateway_route_table_association" "this" { - for_each = { - for k, v in var.vpc_attachments : k => v if var.create_tgw && var.create_tgw_routes && try(v.transit_gateway_default_route_table_association, true) != true - } +resource "aws_ec2_transit_gateway_peering_attachment_accepter" "this" { + for_each = { for k, v in var.peering_attachments : k => v if var.create && v.accept_peering_attachment } - # Create association if it was not set already by aws_ec2_transit_gateway_vpc_attachment resource - transit_gateway_attachment_id = aws_ec2_transit_gateway_vpc_attachment.this[each.key].id - transit_gateway_route_table_id = var.create_tgw ? aws_ec2_transit_gateway_route_table.this[0].id : try(each.value.transit_gateway_route_table_id, var.transit_gateway_route_table_id) -} + transit_gateway_attachment_id = aws_ec2_transit_gateway_peering_attachment.this[each.key].id -resource "aws_ec2_transit_gateway_route_table_propagation" "this" { - for_each = { - for k, v in var.vpc_attachments : k => v if var.create_tgw && var.create_tgw_routes && try(v.transit_gateway_default_route_table_propagation, true) != true - } - - # Create association if it was not set already by aws_ec2_transit_gateway_vpc_attachment resource - transit_gateway_attachment_id = aws_ec2_transit_gateway_vpc_attachment.this[each.key].id - transit_gateway_route_table_id = var.create_tgw ? aws_ec2_transit_gateway_route_table.this[0].id : try(each.value.transit_gateway_route_table_id, var.transit_gateway_route_table_id) + tags = merge( + var.tags, + each.value.tags, + ) } ################################################################################ # Resource Access Manager ################################################################################ +locals { + ram_name = try(coalesce(var.ram_name, var.name), "") +} + resource "aws_ram_resource_share" "this" { - count = var.create_tgw && var.share_tgw ? 1 : 0 + count = var.create && var.enable_ram_share ? 1 : 0 - name = coalesce(var.ram_name, var.name) + name = local.ram_name allow_external_principals = var.ram_allow_external_principals tags = merge( var.tags, - { Name = coalesce(var.ram_name, var.name) }, + { Name = local.ram_name }, var.ram_tags, ) } resource "aws_ram_resource_association" "this" { - count = var.create_tgw && var.share_tgw ? 1 : 0 + count = var.create && var.enable_ram_share ? 1 : 0 resource_arn = aws_ec2_transit_gateway.this[0].arn resource_share_arn = aws_ram_resource_share.this[0].id } resource "aws_ram_principal_association" "this" { - count = var.create_tgw && var.share_tgw ? length(var.ram_principals) : 0 + for_each = { for k, v in var.ram_principals : k => v if var.create && var.enable_ram_share } - principal = var.ram_principals[count.index] + principal = each.value resource_share_arn = aws_ram_resource_share.this[0].arn } -resource "aws_ram_resource_share_accepter" "this" { - count = !var.create_tgw && var.share_tgw ? 1 : 0 +################################################################################ +# Flow Log(s) +################################################################################ + +resource "aws_flow_log" "this" { + for_each = { for k, v in var.flow_logs : k => v if var.create && var.create_flow_log } - share_arn = var.ram_resource_share_arn + deliver_cross_account_role = each.value.deliver_cross_account_role + + dynamic "destination_options" { + for_each = each.value.destination_options != null ? [each.value.destination_options] : [] + + content { + file_format = destination_options.value.file_format + hive_compatible_partitions = destination_options.value.hive_compatible_partitions + per_hour_partition = destination_options.value.per_hour_partition + } + } + + iam_role_arn = each.value.iam_role_arn + log_destination = each.value.log_destination + log_destination_type = each.value.log_destination_type + log_format = each.value.log_format + max_aggregation_interval = max(each.value.max_aggregation_interval, 60) + + traffic_type = each.value.traffic_type + transit_gateway_id = each.value.enable_transit_gateway ? aws_ec2_transit_gateway.this[0].id : null + transit_gateway_attachment_id = each.value.enable_transit_gateway ? null : try( + aws_ec2_transit_gateway_vpc_attachment.this[each.value.vpc_attachment_key].id, + aws_ec2_transit_gateway_peering_attachment.this[each.value.peering_attachment_key].id, + null + ) + + tags = merge( + var.tags, + each.value.tags, + ) } diff --git a/modules/route-table/README.md b/modules/route-table/README.md new file mode 100644 index 0000000..338623d --- /dev/null +++ b/modules/route-table/README.md @@ -0,0 +1,114 @@ +# AWS Transit Gateway Route Table Terraform module + +Terraform module which creates AWS Transit Gateway route table and route resources. + +## Usage + +```hcl +module "transit_gateway" { + source = "terraform-aws-modules/transit-gateway/aws" + + name = "example" + description = "Example TGW connecting multiple VPCs" + + # Truncated for brevity ... +} + +module "transit_gateway_route_table" { + source = "terraform-aws-modules/transit-gateway/aws//modules/route-table" + + name = "example" + transit_gateway_id = module.transit_gateway.id + + associations = { + vpc1 = { + transit_gateway_attachment_id = module.transit_gateway.vpc_attachments["vpc1"].id + propagate_route_table = true + } + vpc2 = { + transit_gateway_attachment_id = module.transit_gateway.vpc_attachments["vpc2"].id + propagate_route_table = true + } + } + + routes = { + blackhole = { + blackhole = true + destination_cidr_block = "0.0.0.0/0" + } + } + + vpc_routes = { + vpc1 = { + destination_cidr_block = "10.0.0.0/16" + route_table_id = "rtb-a73c2ede" + } + vpc2 = { + destination_cidr_block = 10.1.0.0/16" + route_table_id = "rtb-852956e2", + } + } + + tags = { + Environment = "Development" + Project = "Example" + } +} +``` + +## Examples + +- [Complete example](https://github.com/terraform-aws-modules/terraform-aws-transit-gateway/tree/master/examples/complete) shows TGW in combination with the [VPC module](https://github.com/terraform-aws-modules/terraform-aws-vpc). +- [Multi-account example](https://github.com/terraform-aws-modules/terraform-aws-transit-gateway/tree/master/examples/multi-account) shows TGW resources shared with different AWS accounts (via [Resource Access Manager (RAM)](https://aws.amazon.com/ram/)). + + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.3 | +| [aws](#requirement\_aws) | >= 5.78 | + +## Providers + +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | >= 5.78 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [aws_ec2_transit_gateway_route.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_transit_gateway_route) | resource | +| [aws_ec2_transit_gateway_route_table.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_transit_gateway_route_table) | resource | +| [aws_ec2_transit_gateway_route_table_association.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_transit_gateway_route_table_association) | resource | +| [aws_ec2_transit_gateway_route_table_propagation.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_transit_gateway_route_table_propagation) | resource | +| [aws_route.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [associations](#input\_associations) | A map of transit gateway attachment IDs to associate with the Transit Gateway route table |
map(object({
transit_gateway_attachment_id = optional(string)
replace_existing_association = optional(bool)
propagate_route_table = optional(bool, false)
}))
| `{}` | no | +| [create](#input\_create) | Controls if resources should be created (it affects almost all resources) | `bool` | `true` | no | +| [name](#input\_name) | Name to be used on all the resources as identifier | `string` | `""` | no | +| [routes](#input\_routes) | A map of Transit Gateway routes to create in the route table |
map(object({
destination_cidr_block = string
blackhole = optional(bool, false)
transit_gateway_attachment_id = optional(string)
}))
| `{}` | no | +| [tags](#input\_tags) | A map of tags to add to all resources | `map(string)` | `{}` | no | +| [transit\_gateway\_id](#input\_transit\_gateway\_id) | The ID of the EC2 Transit Gateway | `string` | `""` | no | +| [vpc\_routes](#input\_vpc\_routes) | A map of VPC routes to create in the route table provided |
map(object({
route_table_id = string
destination_cidr_block = optional(string)
destination_ipv6_cidr_block = optional(string)
}))
| `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [arn](#output\_arn) | EC2 Transit Gateway Route Table Amazon Resource Name (ARN) | +| [id](#output\_id) | EC2 Transit Gateway Route Table identifier | + + +## License + +Apache 2 Licensed. See [LICENSE](https://github.com/terraform-aws-modules/terraform-aws-transit-gateway/tree/master/LICENSE) for full details. diff --git a/modules/route-table/main.tf b/modules/route-table/main.tf new file mode 100644 index 0000000..b9e7437 --- /dev/null +++ b/modules/route-table/main.tf @@ -0,0 +1,52 @@ +################################################################################ +# Route Table +################################################################################ + +resource "aws_ec2_transit_gateway_route_table" "this" { + count = var.create ? 1 : 0 + + transit_gateway_id = var.transit_gateway_id + + tags = merge( + var.tags, + { Name = var.name } + ) +} + +resource "aws_ec2_transit_gateway_route_table_association" "this" { + for_each = { for k, v in var.associations : k => v if var.create } + + transit_gateway_attachment_id = each.value.transit_gateway_attachment_id + transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.this[0].id + replace_existing_association = try(each.value.replace_existing_association, null) +} + +resource "aws_ec2_transit_gateway_route_table_propagation" "this" { + for_each = { for k, v in var.associations : k => v if var.create && try(v.propagate_route_table, false) } + + transit_gateway_attachment_id = each.value.transit_gateway_attachment_id + transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.this[0].id +} + +################################################################################ +# Route(s) +################################################################################ + +resource "aws_ec2_transit_gateway_route" "this" { + for_each = { for k, v in var.routes : k => v if var.create } + + destination_cidr_block = each.value.destination_cidr_block + blackhole = each.value.blackhole + + transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.this[0].id + transit_gateway_attachment_id = each.value.transit_gateway_attachment_id +} + +resource "aws_route" "this" { + for_each = { for k, v in var.vpc_routes : k => v if var.create } + + route_table_id = each.value.route_table_id + destination_cidr_block = each.value.destination_cidr_block + destination_ipv6_cidr_block = each.value.destination_ipv6_cidr_block + transit_gateway_id = var.transit_gateway_id +} diff --git a/modules/route-table/outputs.tf b/modules/route-table/outputs.tf new file mode 100644 index 0000000..7709c33 --- /dev/null +++ b/modules/route-table/outputs.tf @@ -0,0 +1,13 @@ +################################################################################ +# Route Table +################################################################################ + +output "arn" { + description = "EC2 Transit Gateway Route Table Amazon Resource Name (ARN)" + value = try(aws_ec2_transit_gateway_route_table.this[0].arn, null) +} + +output "id" { + description = "EC2 Transit Gateway Route Table identifier" + value = try(aws_ec2_transit_gateway_route_table.this[0].id, null) +} diff --git a/modules/route-table/variables.tf b/modules/route-table/variables.tf new file mode 100644 index 0000000..137a4e8 --- /dev/null +++ b/modules/route-table/variables.tf @@ -0,0 +1,61 @@ +variable "create" { + description = "Controls if resources should be created (it affects almost all resources)" + type = bool + default = true +} + +variable "name" { + description = "Name to be used on all the resources as identifier" + type = string + default = "" +} + +variable "tags" { + description = "A map of tags to add to all resources" + type = map(string) + default = {} +} + +################################################################################ +# Route Table +################################################################################ + +variable "transit_gateway_id" { + description = "The ID of the EC2 Transit Gateway" + type = string + default = "" +} + +variable "associations" { + description = "A map of transit gateway attachment IDs to associate with the Transit Gateway route table" + type = map(object({ + transit_gateway_attachment_id = optional(string) + replace_existing_association = optional(bool) + propagate_route_table = optional(bool, false) + })) + default = {} +} + +################################################################################ +# Route(s) +################################################################################ + +variable "routes" { + description = "A map of Transit Gateway routes to create in the route table" + type = map(object({ + destination_cidr_block = string + blackhole = optional(bool, false) + transit_gateway_attachment_id = optional(string) + })) + default = {} +} + +variable "vpc_routes" { + description = "A map of VPC routes to create in the route table provided" + type = map(object({ + route_table_id = string + destination_cidr_block = optional(string) + destination_ipv6_cidr_block = optional(string) + })) + default = {} +} diff --git a/modules/route-table/versions.tf b/modules/route-table/versions.tf new file mode 100644 index 0000000..1731e40 --- /dev/null +++ b/modules/route-table/versions.tf @@ -0,0 +1,10 @@ +terraform { + required_version = ">= 1.3" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.78" + } + } +} diff --git a/outputs.tf b/outputs.tf index 8dcb8a5..27d0f84 100644 --- a/outputs.tf +++ b/outputs.tf @@ -2,99 +2,54 @@ # Transit Gateway ################################################################################ -output "ec2_transit_gateway_arn" { +output "arn" { description = "EC2 Transit Gateway Amazon Resource Name (ARN)" - value = try(aws_ec2_transit_gateway.this[0].arn, "") + value = try(aws_ec2_transit_gateway.this[0].arn, null) } -output "ec2_transit_gateway_id" { +output "id" { description = "EC2 Transit Gateway identifier" - value = try(aws_ec2_transit_gateway.this[0].id, "") + value = try(aws_ec2_transit_gateway.this[0].id, null) } -output "ec2_transit_gateway_owner_id" { +output "owner_id" { description = "Identifier of the AWS account that owns the EC2 Transit Gateway" - value = try(aws_ec2_transit_gateway.this[0].owner_id, "") + value = try(aws_ec2_transit_gateway.this[0].owner_id, null) } -output "ec2_transit_gateway_association_default_route_table_id" { +output "association_default_route_table_id" { description = "Identifier of the default association route table" - value = try(aws_ec2_transit_gateway.this[0].association_default_route_table_id, "") + value = try(aws_ec2_transit_gateway.this[0].association_default_route_table_id, null) } -output "ec2_transit_gateway_propagation_default_route_table_id" { +output "propagation_default_route_table_id" { description = "Identifier of the default propagation route table" - value = try(aws_ec2_transit_gateway.this[0].propagation_default_route_table_id, "") + value = try(aws_ec2_transit_gateway.this[0].propagation_default_route_table_id, null) } ################################################################################ -# VPC Attachment +# Resource Access Manager ################################################################################ -output "ec2_transit_gateway_vpc_attachment_ids" { - description = "List of EC2 Transit Gateway VPC Attachment identifiers" - value = [for k, v in aws_ec2_transit_gateway_vpc_attachment.this : v.id] -} - -output "ec2_transit_gateway_vpc_attachment" { - description = "Map of EC2 Transit Gateway VPC Attachment attributes" - value = aws_ec2_transit_gateway_vpc_attachment.this +output "ram_resource_share_id" { + description = "The Amazon Resource Name (ARN) of the resource share" + value = try(aws_ram_resource_share.this[0].id, null) } ################################################################################ -# Route Table / Routes +# VPC Attachment ################################################################################ -output "ec2_transit_gateway_route_table_id" { - description = "EC2 Transit Gateway Route Table identifier" - value = try(aws_ec2_transit_gateway_route_table.this[0].id, "") -} - -output "ec2_transit_gateway_route_table_default_association_route_table" { - description = "Boolean whether this is the default association route table for the EC2 Transit Gateway" - value = try(aws_ec2_transit_gateway_route_table.this[0].default_association_route_table, "") -} - -output "ec2_transit_gateway_route_table_default_propagation_route_table" { - description = "Boolean whether this is the default propagation route table for the EC2 Transit Gateway" - value = try(aws_ec2_transit_gateway_route_table.this[0].default_propagation_route_table, "") -} - -output "ec2_transit_gateway_route_ids" { - description = "List of EC2 Transit Gateway Route Table identifier combined with destination" - value = aws_ec2_transit_gateway_route.this[*].id -} - -output "ec2_transit_gateway_route_table_association_ids" { - description = "List of EC2 Transit Gateway Route Table Association identifiers" - value = [for k, v in aws_ec2_transit_gateway_route_table_association.this : v.id] -} - -output "ec2_transit_gateway_route_table_association" { - description = "Map of EC2 Transit Gateway Route Table Association attributes" - value = aws_ec2_transit_gateway_route_table_association.this -} - -output "ec2_transit_gateway_route_table_propagation_ids" { - description = "List of EC2 Transit Gateway Route Table Propagation identifiers" - value = [for k, v in aws_ec2_transit_gateway_route_table_propagation.this : v.id] -} - -output "ec2_transit_gateway_route_table_propagation" { - description = "Map of EC2 Transit Gateway Route Table Propagation attributes" - value = aws_ec2_transit_gateway_route_table_propagation.this +output "vpc_attachments" { + description = "Map of VPC attachments created" + value = aws_ec2_transit_gateway_vpc_attachment.this } ################################################################################ -# Resource Access Manager +# TGW Peering Attachment ################################################################################ -output "ram_resource_share_id" { - description = "The Amazon Resource Name (ARN) of the resource share" - value = try(aws_ram_resource_share.this[0].id, "") -} - -output "ram_principal_association_id" { - description = "The Amazon Resource Name (ARN) of the Resource Share and the principal, separated by a comma" - value = try(aws_ram_principal_association.this[0].id, "") +output "peering_attachments" { + description = "Map of TGW peering attachments created" + value = aws_ec2_transit_gateway_peering_attachment.this } diff --git a/variables.tf b/variables.tf index da01c9d..aaa2b56 100644 --- a/variables.tf +++ b/variables.tf @@ -1,5 +1,11 @@ +variable "create" { + description = "Controls if resources should be created (it affects almost all resources)" + type = bool + default = true +} + variable "name" { - description = "Name to be used on all the resources as identifier" + description = "Name to be used on all the resources as the identifier" type = string default = "" } @@ -14,58 +20,52 @@ variable "tags" { # Transit Gateway ################################################################################ -variable "create_tgw" { - description = "Controls if TGW should be created (it affects almost all resources)" - type = bool - default = true -} - -variable "description" { - description = "Description of the EC2 Transit Gateway" - type = string - default = null -} - variable "amazon_side_asn" { - description = "The Autonomous System Number (ASN) for the Amazon side of the gateway. By default the TGW is created with the current default Amazon ASN." + description = "The Autonomous System Number (ASN) for the Amazon side of the gateway. By default the TGW is created with the current default Amazon ASN" type = string default = null } -variable "enable_default_route_table_association" { - description = "Whether resource attachments are automatically associated with the default association route table" +variable "auto_accept_shared_attachments" { + description = "Whether resource attachment requests are automatically accepted" type = bool default = true } -variable "enable_default_route_table_propagation" { - description = "Whether resource attachments automatically propagate routes to the default propagation route table" +variable "default_route_table_association" { + description = "Whether resource attachments are automatically associated with the default association route table" type = bool - default = true + default = false } -variable "enable_auto_accept_shared_attachments" { - description = "Whether resource attachment requests are automatically accepted" +variable "default_route_table_propagation" { + description = "Whether resource attachments automatically propagate routes to the default propagation route table" type = bool default = false } -variable "enable_vpn_ecmp_support" { - description = "Whether VPN Equal Cost Multipath Protocol support is enabled" +variable "description" { + description = "Description of the EC2 Transit Gateway" + type = string + default = null +} + +variable "dns_support" { + description = "Should be true to enable DNS support in the TGW" type = bool default = true } -variable "enable_multicast_support" { +variable "multicast_support" { description = "Whether multicast support is enabled" type = bool default = false } -variable "enable_dns_support" { - description = "Should be true to enable DNS support in the TGW" +variable "security_group_referencing_support" { + description = "Whether security group referencing is enabled" type = bool - default = true + default = false } variable "transit_gateway_cidr_blocks" { @@ -74,6 +74,12 @@ variable "transit_gateway_cidr_blocks" { default = [] } +variable "vpn_ecmp_support" { + description = "Whether VPN Equal Cost Multipath Protocol support is enabled" + type = bool + default = true +} + variable "timeouts" { description = "Create, update, and delete timeout configurations for the transit gateway" type = map(string) @@ -86,64 +92,49 @@ variable "tgw_tags" { default = {} } -variable "tgw_default_route_table_tags" { - description = "Additional tags for the Default TGW route table" - type = map(string) - default = {} -} - -variable "enable_sg_referencing_support" { - description = "Indicates whether to enable security group referencing support" - type = bool - default = true -} - ################################################################################ # VPC Attachment ################################################################################ variable "vpc_attachments" { - description = "Maps of maps of VPC details to attach to TGW. Type 'any' to disable type validation by Terraform." - type = any - default = {} -} - -variable "tgw_vpc_attachment_tags" { - description = "Additional tags for VPC attachments" - type = map(string) - default = {} -} - -################################################################################ -# Route Table / Routes -################################################################################ - -variable "create_tgw_routes" { - description = "Controls if TGW Route Table / Routes should be created" - type = bool - default = true -} - -variable "transit_gateway_route_table_id" { - description = "Identifier of EC2 Transit Gateway Route Table to use with the Target Gateway when reusing it between multiple TGWs" - type = string - default = null -} - -variable "tgw_route_table_tags" { - description = "Additional tags for the TGW route table" - type = map(string) - default = {} + description = "Map of VPC route table attachments to create" + type = map(object({ + appliance_mode_support = optional(bool, false) + dns_support = optional(bool, true) + ipv6_support = optional(bool, false) + security_group_referencing_support = optional(bool, false) + subnet_ids = list(string) + tags = optional(map(string), {}) + transit_gateway_default_route_table_association = optional(bool, false) + transit_gateway_default_route_table_propagation = optional(bool, false) + vpc_id = string + + accept_peering_attachment = optional(bool, false) + })) + default = {} +} + +variable "peering_attachments" { + description = "Map of Transit Gateway peering attachments to create" + type = map(object({ + peer_account_id = string + peer_region = string + peer_transit_gateway_id = string + tags = optional(map(string), {}) + + accept_peering_attachment = optional(bool, false) + })) + default = {} } ################################################################################ # Resource Access Manager ################################################################################ -variable "share_tgw" { +variable "enable_ram_share" { description = "Whether to share your transit gateway with other accounts" type = bool - default = true + default = false } variable "ram_name" { @@ -153,25 +144,54 @@ variable "ram_name" { } variable "ram_allow_external_principals" { - description = "Indicates whether principals outside your organization can be associated with a resource share." + description = "Indicates whether principals outside your organization can be associated with a resource share" type = bool default = false } variable "ram_principals" { description = "A list of principals to share TGW with. Possible values are an AWS account ID, an AWS Organizations Organization ARN, or an AWS Organizations Organization Unit ARN" - type = list(string) + type = set(string) default = [] } -variable "ram_resource_share_arn" { - description = "ARN of RAM resource share" - type = string - default = "" -} - variable "ram_tags" { description = "Additional tags for the RAM" type = map(string) default = {} } + +################################################################################ +# Flow Logs +################################################################################ + +variable "create_flow_log" { + description = "Whether to create flow log resource(s)" + type = bool + default = true +} + +variable "flow_logs" { + description = "Flow Logs to create for Transit Gateway or attachments" + type = map(object({ + deliver_cross_account_role = optional(string) + destination_options = optional(object({ + file_format = optional(string, "parquet") + hive_compatible_partitions = optional(bool, false) + per_hour_partition = optional(bool, true) + })) + iam_role_arn = optional(string) + log_destination = optional(string) + log_destination_type = optional(string) + log_format = optional(string) + max_aggregation_interval = optional(number, 30) + traffic_type = optional(string, "ALL") + tags = optional(map(string), {}) + + enable_transit_gateway = optional(bool, true) + # The following can be provided when `enable_transit_gateway` is `false` + vpc_attachment_key = optional(string) + peering_attachment_key = optional(string) + })) + default = {} +} diff --git a/versions.tf b/versions.tf index 03533eb..1731e40 100644 --- a/versions.tf +++ b/versions.tf @@ -1,10 +1,10 @@ terraform { - required_version = ">= 0.13.1" + required_version = ">= 1.3" required_providers { aws = { source = "hashicorp/aws" - version = ">= 4.4" + version = ">= 5.78" } } }