Skip to content

Commit 576b717

Browse files
authored
feat: adds tagging the TGW attachment + associating / propagating TGW RTB + creating TGW routes (#37)
* fix: uses correct type with var.vpn_connection_static_routes_only (bool > string) I could not find why this was originally implemented this way... Maybe a 0.11 holdover? It was bugging me. * fix: vpc_id should not be required (not required if doing a TGW <> VPN connection) * feat: adds tagging the TGW attachment + associating / propagating TGW RTB + creating TGW routes * chore: readme updates * chore: cleans up tflint issues 🎉 * fix: adds sensitive = true for gateway_config output (fixes #36)
1 parent d7abec2 commit 576b717

File tree

8 files changed

+202
-223
lines changed

8 files changed

+202
-223
lines changed

README.md

+99-191
Large diffs are not rendered by default.

docs/terraform.md

+10-4
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@
33

44
| Name | Version |
55
|------|---------|
6-
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 0.13.0 |
6+
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.3.0 |
77
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 2.0 |
8-
| <a name="requirement_null"></a> [null](#requirement\_null) | >= 2.0 |
98

109
## Providers
1110

@@ -24,6 +23,10 @@
2423
| Name | Type |
2524
|------|------|
2625
| [aws_customer_gateway.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/customer_gateway) | resource |
26+
| [aws_ec2_tag.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_tag) | resource |
27+
| [aws_ec2_transit_gateway_route.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_transit_gateway_route) | resource |
28+
| [aws_ec2_transit_gateway_route_table_association.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_transit_gateway_route_table_association) | resource |
29+
| [aws_ec2_transit_gateway_route_table_propagation.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_transit_gateway_route_table_propagation) | resource |
2730
| [aws_vpn_connection.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpn_connection) | resource |
2831
| [aws_vpn_connection_route.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpn_connection_route) | resource |
2932
| [aws_vpn_gateway.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpn_gateway) | resource |
@@ -56,11 +59,13 @@
5659
| <a name="input_tags"></a> [tags](#input\_tags) | Additional tags (e.g. `{'BusinessUnit': 'XYZ'}`).<br>Neither the tag keys nor the tag values will be modified by this module. | `map(string)` | `{}` | no |
5760
| <a name="input_tenant"></a> [tenant](#input\_tenant) | ID element \_(Rarely used, not included by default)\_. A customer identifier, indicating who this instance of a resource is for | `string` | `null` | no |
5861
| <a name="input_transit_gateway_enabled"></a> [transit\_gateway\_enabled](#input\_transit\_gateway\_enabled) | Set to true to enable VPN connection to transit gateway and then pass in the existing\_transit\_gateway\_id | `bool` | `false` | no |
59-
| <a name="input_vpc_id"></a> [vpc\_id](#input\_vpc\_id) | The ID of the VPC to which the Virtual Private Gateway will be attached | `string` | n/a | yes |
62+
| <a name="input_transit_gateway_route_table_id"></a> [transit\_gateway\_route\_table\_id](#input\_transit\_gateway\_route\_table\_id) | The ID of the route table for the transit gateway that you want to associate + propogate the VPN connection's TGW attachment | `string` | `null` | no |
63+
| <a name="input_transit_gateway_routes"></a> [transit\_gateway\_routes](#input\_transit\_gateway\_routes) | A map of transit gateway routes to create on the given TGW route table (via `transit_gateway_route_table_id`) for the created VPN Attachment. Use the key in the map to describe the route. | <pre>map(object({<br> blackhole = optional(bool, false)<br> destination_cidr_block = string<br> }))</pre> | `{}` | no |
64+
| <a name="input_vpc_id"></a> [vpc\_id](#input\_vpc\_id) | The ID of the VPC to which the Virtual Private Gateway will be attached | `string` | `null` | no |
6065
| <a name="input_vpn_connection_local_ipv4_network_cidr"></a> [vpn\_connection\_local\_ipv4\_network\_cidr](#input\_vpn\_connection\_local\_ipv4\_network\_cidr) | The IPv4 CIDR on the customer gateway (on-premises) side of the VPN connection. | `string` | `"0.0.0.0/0"` | no |
6166
| <a name="input_vpn_connection_remote_ipv4_network_cidr"></a> [vpn\_connection\_remote\_ipv4\_network\_cidr](#input\_vpn\_connection\_remote\_ipv4\_network\_cidr) | The IPv4 CIDR on the AWS side of the VPN connection. | `string` | `"0.0.0.0/0"` | no |
6267
| <a name="input_vpn_connection_static_routes_destinations"></a> [vpn\_connection\_static\_routes\_destinations](#input\_vpn\_connection\_static\_routes\_destinations) | List of CIDR blocks to be used as destination for static routes. Routes to destinations will be propagated to the route tables defined in `route_table_ids` | `list(string)` | `[]` | no |
63-
| <a name="input_vpn_connection_static_routes_only"></a> [vpn\_connection\_static\_routes\_only](#input\_vpn\_connection\_static\_routes\_only) | If set to `true`, the VPN connection will use static routes exclusively. Static routes must be used for devices that don't support BGP | `string` | `"true"` | no |
68+
| <a name="input_vpn_connection_static_routes_only"></a> [vpn\_connection\_static\_routes\_only](#input\_vpn\_connection\_static\_routes\_only) | If set to `true`, the VPN connection will use static routes exclusively. Static routes must be used for devices that don't support BGP | `bool` | `false` | no |
6469
| <a name="input_vpn_connection_tunnel1_dpd_timeout_action"></a> [vpn\_connection\_tunnel1\_dpd\_timeout\_action](#input\_vpn\_connection\_tunnel1\_dpd\_timeout\_action) | The action to take after DPD timeout occurs for the first VPN tunnel. Specify restart to restart the IKE initiation. Specify clear to end the IKE session. Valid values are clear \| none \| restart. | `string` | `"clear"` | no |
6570
| <a name="input_vpn_connection_tunnel1_ike_versions"></a> [vpn\_connection\_tunnel1\_ike\_versions](#input\_vpn\_connection\_tunnel1\_ike\_versions) | The IKE versions that are permitted for the first VPN tunnel. Valid values are ikev1 \| ikev2. | `list(string)` | `[]` | no |
6671
| <a name="input_vpn_connection_tunnel1_inside_cidr"></a> [vpn\_connection\_tunnel1\_inside\_cidr](#input\_vpn\_connection\_tunnel1\_inside\_cidr) | The CIDR block of the inside IP addresses for the first VPN tunnel | `string` | `null` | no |
@@ -90,6 +95,7 @@
9095
| Name | Description |
9196
|------|-------------|
9297
| <a name="output_customer_gateway_id"></a> [customer\_gateway\_id](#output\_customer\_gateway\_id) | Customer Gateway ID |
98+
| <a name="output_transit_gateway_attachment_id"></a> [transit\_gateway\_attachment\_id](#output\_transit\_gateway\_attachment\_id) | The ID of the transit gateway attachment for the VPN connection (if a TGW connection) |
9399
| <a name="output_vpn_connection_customer_gateway_configuration"></a> [vpn\_connection\_customer\_gateway\_configuration](#output\_vpn\_connection\_customer\_gateway\_configuration) | The configuration information for the VPN connection's Customer Gateway (in the native XML format) |
94100
| <a name="output_vpn_connection_id"></a> [vpn\_connection\_id](#output\_vpn\_connection\_id) | VPN Connection ID |
95101
| <a name="output_vpn_connection_tunnel1_address"></a> [vpn\_connection\_tunnel1\_address](#output\_vpn\_connection\_tunnel1\_address) | The public IP address of the first VPN tunnel |

examples/complete/outputs.tf

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ output "vpn_connection_id" {
1515

1616
output "vpn_connection_customer_gateway_configuration" {
1717
description = "The configuration information for the VPN connection's Customer Gateway (in the native XML format)"
18+
sensitive = true
1819
value = module.vpn_connection.vpn_connection_customer_gateway_configuration
1920
}
2021

examples/complete/versions.tf

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
terraform {
2-
required_version = ">= 0.13.0"
2+
required_version = ">= 1.3.0"
3+
34
required_providers {
45
aws = {
5-
source = "hashicorp/aws"
6+
source = "hashicorp/aws"
7+
version = ">= 2.0"
68
}
79
}
810
}

main.tf

+52-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
locals {
22
enabled = module.this.enabled
3+
4+
transit_gateway_enabled = local.enabled && var.transit_gateway_enabled
5+
6+
transit_gateway_attachment_id = join("", aws_vpn_connection.default[*].transit_gateway_attachment_id)
7+
vpn_gateway_id = join("", aws_vpn_gateway.default[*].id)
8+
customer_gateway_id = join("", aws_customer_gateway.default[*].id)
9+
vpn_connection_id = join("", aws_vpn_connection.default[*].id)
310
}
411

512
# https://www.terraform.io/docs/providers/aws/r/vpn_gateway.html
@@ -22,9 +29,9 @@ resource "aws_customer_gateway" "default" {
2229
# https://www.terraform.io/docs/providers/aws/r/vpn_connection.html
2330
resource "aws_vpn_connection" "default" {
2431
count = local.enabled ? 1 : 0
25-
vpn_gateway_id = var.transit_gateway_enabled == false ? join("", aws_vpn_gateway.default.*.id) : null
26-
customer_gateway_id = join("", aws_customer_gateway.default.*.id)
27-
transit_gateway_id = var.transit_gateway_enabled ? var.existing_transit_gateway_id : null
32+
vpn_gateway_id = local.transit_gateway_enabled == false ? local.vpn_gateway_id : null
33+
customer_gateway_id = local.customer_gateway_id
34+
transit_gateway_id = local.transit_gateway_enabled ? var.existing_transit_gateway_id : null
2835
type = "ipsec.1"
2936
static_routes_only = var.vpn_connection_static_routes_only
3037
local_ipv4_network_cidr = var.vpn_connection_local_ipv4_network_cidr
@@ -62,13 +69,52 @@ resource "aws_vpn_connection" "default" {
6269
# https://www.terraform.io/docs/providers/aws/r/vpn_gateway_route_propagation.html
6370
resource "aws_vpn_gateway_route_propagation" "default" {
6471
count = local.enabled ? length(var.route_table_ids) : 0
65-
vpn_gateway_id = join("", aws_vpn_gateway.default.*.id)
72+
vpn_gateway_id = local.vpn_gateway_id
6673
route_table_id = element(var.route_table_ids, count.index)
6774
}
6875

6976
# https://www.terraform.io/docs/providers/aws/r/vpn_connection_route.html
7077
resource "aws_vpn_connection_route" "default" {
71-
count = local.enabled && var.vpn_connection_static_routes_only == "true" ? length(var.vpn_connection_static_routes_destinations) : 0
72-
vpn_connection_id = join("", aws_vpn_connection.default.*.id)
78+
count = local.enabled && var.vpn_connection_static_routes_only ? length(var.vpn_connection_static_routes_destinations) : 0
79+
vpn_connection_id = local.vpn_connection_id
7380
destination_cidr_block = element(var.vpn_connection_static_routes_destinations, count.index)
7481
}
82+
83+
## Transit Gateway VPN Connection Attachments
84+
85+
# Required to tag VPN Connection TGW Attachments out of bound of the VPN Connection resource
86+
# If we do not do this, the TGW Attachment will not have a name tag or any tags, which makes it difficult to identify in the console.
87+
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_tag
88+
resource "aws_ec2_tag" "default" {
89+
for_each = local.transit_gateway_enabled ? module.this.tags : {}
90+
91+
resource_id = local.transit_gateway_attachment_id
92+
key = each.key
93+
value = each.value
94+
}
95+
96+
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_transit_gateway_route_table_association
97+
resource "aws_ec2_transit_gateway_route_table_association" "default" {
98+
count = local.transit_gateway_enabled && var.transit_gateway_route_table_id != null ? 1 : 0
99+
100+
transit_gateway_attachment_id = local.transit_gateway_attachment_id
101+
transit_gateway_route_table_id = var.transit_gateway_route_table_id
102+
}
103+
104+
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_transit_gateway_route_table_propagation
105+
resource "aws_ec2_transit_gateway_route_table_propagation" "default" {
106+
count = local.transit_gateway_enabled && var.transit_gateway_route_table_id != null ? 1 : 0
107+
108+
transit_gateway_attachment_id = local.transit_gateway_attachment_id
109+
transit_gateway_route_table_id = var.transit_gateway_route_table_id
110+
}
111+
112+
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_transit_gateway_route
113+
resource "aws_ec2_transit_gateway_route" "default" {
114+
for_each = local.transit_gateway_enabled && var.transit_gateway_route_table_id != null ? var.transit_gateway_routes : {}
115+
116+
blackhole = each.value.blackhole
117+
destination_cidr_block = each.value.destination_cidr_block
118+
transit_gateway_attachment_id = local.transit_gateway_attachment_id
119+
transit_gateway_route_table_id = var.transit_gateway_route_table_id
120+
}

outputs.tf

+16-13
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,56 @@
11
output "vpn_gateway_id" {
22
description = "Virtual Private Gateway ID"
3-
value = join("", aws_vpn_gateway.default.*.id)
3+
value = local.vpn_gateway_id
44
}
55

66
output "customer_gateway_id" {
77
description = "Customer Gateway ID"
8-
value = join("", aws_customer_gateway.default.*.id)
8+
value = local.customer_gateway_id
99
}
1010

1111
output "vpn_connection_id" {
1212
description = "VPN Connection ID"
13-
value = join("", aws_vpn_connection.default.*.id)
13+
value = local.vpn_connection_id
1414
}
1515

1616
output "vpn_connection_customer_gateway_configuration" {
1717
description = "The configuration information for the VPN connection's Customer Gateway (in the native XML format)"
18-
value = join(
19-
"",
20-
aws_vpn_connection.default.*.customer_gateway_configuration,
21-
)
18+
sensitive = true
19+
value = join("", aws_vpn_connection.default[*].customer_gateway_configuration)
2220
}
2321

2422
output "vpn_connection_tunnel1_address" {
2523
description = "The public IP address of the first VPN tunnel"
26-
value = join("", aws_vpn_connection.default.*.tunnel1_address)
24+
value = join("", aws_vpn_connection.default[*].tunnel1_address)
2725
}
2826

2927
output "vpn_connection_tunnel1_cgw_inside_address" {
3028
description = "The RFC 6890 link-local address of the first VPN tunnel (Customer Gateway side)"
31-
value = join("", aws_vpn_connection.default.*.tunnel1_cgw_inside_address)
29+
value = join("", aws_vpn_connection.default[*].tunnel1_cgw_inside_address)
3230
}
3331

3432
output "vpn_connection_tunnel1_vgw_inside_address" {
3533
description = "The RFC 6890 link-local address of the first VPN tunnel (Virtual Private Gateway side)"
36-
value = join("", aws_vpn_connection.default.*.tunnel1_vgw_inside_address)
34+
value = join("", aws_vpn_connection.default[*].tunnel1_vgw_inside_address)
3735
}
3836

3937
output "vpn_connection_tunnel2_address" {
4038
description = "The public IP address of the second VPN tunnel"
41-
value = join("", aws_vpn_connection.default.*.tunnel2_address)
39+
value = join("", aws_vpn_connection.default[*].tunnel2_address)
4240
}
4341

4442
output "vpn_connection_tunnel2_cgw_inside_address" {
4543
description = "The RFC 6890 link-local address of the second VPN tunnel (Customer Gateway side)"
46-
value = join("", aws_vpn_connection.default.*.tunnel2_cgw_inside_address)
44+
value = join("", aws_vpn_connection.default[*].tunnel2_cgw_inside_address)
4745
}
4846

4947
output "vpn_connection_tunnel2_vgw_inside_address" {
5048
description = "The RFC 6890 link-local address of the second VPN tunnel (Virtual Private Gateway side)"
51-
value = join("", aws_vpn_connection.default.*.tunnel2_vgw_inside_address)
49+
value = join("", aws_vpn_connection.default[*].tunnel2_vgw_inside_address)
50+
}
51+
52+
output "transit_gateway_attachment_id" {
53+
description = "The ID of the transit gateway attachment for the VPN connection (if a TGW connection)"
54+
value = local.transit_gateway_attachment_id
5255
}
5356

variables.tf

+19-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
variable "vpc_id" {
22
type = string
33
description = "The ID of the VPC to which the Virtual Private Gateway will be attached"
4+
default = null
45
}
56

67
variable "vpn_gateway_amazon_side_asn" {
8+
type = number
79
description = "The Autonomous System Number (ASN) for the Amazon side of the VPN gateway. If you don't specify an ASN, the Virtual Private Gateway is created with the default ASN"
810
default = 64512
911
}
@@ -25,9 +27,9 @@ variable "route_table_ids" {
2527
}
2628

2729
variable "vpn_connection_static_routes_only" {
28-
type = string
30+
type = bool
2931
description = "If set to `true`, the VPN connection will use static routes exclusively. Static routes must be used for devices that don't support BGP"
30-
default = "true"
32+
default = false
3133
}
3234

3335
variable "vpn_connection_static_routes_destinations" {
@@ -191,3 +193,18 @@ variable "transit_gateway_enabled" {
191193
default = false
192194
description = "Set to true to enable VPN connection to transit gateway and then pass in the existing_transit_gateway_id"
193195
}
196+
197+
variable "transit_gateway_route_table_id" {
198+
type = string
199+
default = null
200+
description = "The ID of the route table for the transit gateway that you want to associate + propogate the VPN connection's TGW attachment"
201+
}
202+
203+
variable "transit_gateway_routes" {
204+
type = map(object({
205+
blackhole = optional(bool, false)
206+
destination_cidr_block = string
207+
}))
208+
description = "A map of transit gateway routes to create on the given TGW route table (via `transit_gateway_route_table_id`) for the created VPN Attachment. Use the key in the map to describe the route."
209+
default = {}
210+
}

versions.tf

+1-5
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
terraform {
2-
required_version = ">= 0.13.0"
2+
required_version = ">= 1.3.0"
33

44
required_providers {
55
aws = {
66
source = "hashicorp/aws"
77
version = ">= 2.0"
88
}
9-
null = {
10-
source = "hashicorp/null"
11-
version = ">= 2.0"
12-
}
139
}
1410
}

0 commit comments

Comments
 (0)