Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat: adds tagging the TGW attachment + associating / propagating TGW RTB + creating TGW routes #37

Merged
merged 9 commits into from
Feb 20, 2024
290 changes: 99 additions & 191 deletions README.md

Large diffs are not rendered by default.

14 changes: 10 additions & 4 deletions docs/terraform.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@

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

## Providers

Expand All @@ -24,6 +23,10 @@
| Name | Type |
|------|------|
| [aws_customer_gateway.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/customer_gateway) | resource |
| [aws_ec2_tag.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_tag) | resource |
| [aws_ec2_transit_gateway_route.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_transit_gateway_route) | resource |
| [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 |
| [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 |
| [aws_vpn_connection.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpn_connection) | resource |
| [aws_vpn_connection_route.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpn_connection_route) | resource |
| [aws_vpn_gateway.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpn_gateway) | resource |
Expand Down Expand Up @@ -56,11 +59,13 @@
| <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 |
| <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 |
| <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 |
| <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 |
| <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 |
| <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 |
| <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 |
| <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 |
| <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 |
| <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 |
| <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 |
| <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 |
| <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 |
| <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 |
| <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 |
Expand Down Expand Up @@ -90,6 +95,7 @@
| Name | Description |
|------|-------------|
| <a name="output_customer_gateway_id"></a> [customer\_gateway\_id](#output\_customer\_gateway\_id) | Customer Gateway ID |
| <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) |
| <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) |
| <a name="output_vpn_connection_id"></a> [vpn\_connection\_id](#output\_vpn\_connection\_id) | VPN Connection ID |
| <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 |
Expand Down
1 change: 1 addition & 0 deletions examples/complete/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ output "vpn_connection_id" {

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

Expand Down
6 changes: 4 additions & 2 deletions examples/complete/versions.tf
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
terraform {
required_version = ">= 0.13.0"
required_version = ">= 1.3.0"

required_providers {
aws = {
Gowiem marked this conversation as resolved.
Show resolved Hide resolved
source = "hashicorp/aws"
source = "hashicorp/aws"
version = ">= 2.0"
}
}
}
58 changes: 52 additions & 6 deletions main.tf
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
locals {
enabled = module.this.enabled

transit_gateway_enabled = local.enabled && var.transit_gateway_enabled

transit_gateway_attachment_id = join("", aws_vpn_connection.default[*].transit_gateway_attachment_id)
vpn_gateway_id = join("", aws_vpn_gateway.default[*].id)
customer_gateway_id = join("", aws_customer_gateway.default[*].id)
vpn_connection_id = join("", aws_vpn_connection.default[*].id)
}

# https://www.terraform.io/docs/providers/aws/r/vpn_gateway.html
Expand All @@ -22,9 +29,9 @@ resource "aws_customer_gateway" "default" {
# https://www.terraform.io/docs/providers/aws/r/vpn_connection.html
resource "aws_vpn_connection" "default" {
count = local.enabled ? 1 : 0
vpn_gateway_id = var.transit_gateway_enabled == false ? join("", aws_vpn_gateway.default.*.id) : null
customer_gateway_id = join("", aws_customer_gateway.default.*.id)
transit_gateway_id = var.transit_gateway_enabled ? var.existing_transit_gateway_id : null
vpn_gateway_id = local.transit_gateway_enabled == false ? local.vpn_gateway_id : null
customer_gateway_id = local.customer_gateway_id
transit_gateway_id = local.transit_gateway_enabled ? var.existing_transit_gateway_id : null
type = "ipsec.1"
static_routes_only = var.vpn_connection_static_routes_only
local_ipv4_network_cidr = var.vpn_connection_local_ipv4_network_cidr
Expand Down Expand Up @@ -62,13 +69,52 @@ resource "aws_vpn_connection" "default" {
# https://www.terraform.io/docs/providers/aws/r/vpn_gateway_route_propagation.html
resource "aws_vpn_gateway_route_propagation" "default" {
count = local.enabled ? length(var.route_table_ids) : 0
vpn_gateway_id = join("", aws_vpn_gateway.default.*.id)
vpn_gateway_id = local.vpn_gateway_id
route_table_id = element(var.route_table_ids, count.index)
}

# https://www.terraform.io/docs/providers/aws/r/vpn_connection_route.html
resource "aws_vpn_connection_route" "default" {
count = local.enabled && var.vpn_connection_static_routes_only == "true" ? length(var.vpn_connection_static_routes_destinations) : 0
vpn_connection_id = join("", aws_vpn_connection.default.*.id)
count = local.enabled && var.vpn_connection_static_routes_only ? length(var.vpn_connection_static_routes_destinations) : 0
vpn_connection_id = local.vpn_connection_id
destination_cidr_block = element(var.vpn_connection_static_routes_destinations, count.index)
}

## Transit Gateway VPN Connection Attachments

# Required to tag VPN Connection TGW Attachments out of bound of the VPN Connection resource
# 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.
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_tag
resource "aws_ec2_tag" "default" {
for_each = local.transit_gateway_enabled ? module.this.tags : {}

resource_id = local.transit_gateway_attachment_id
key = each.key
value = each.value
}

# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_transit_gateway_route_table_association
resource "aws_ec2_transit_gateway_route_table_association" "default" {
count = local.transit_gateway_enabled && var.transit_gateway_route_table_id != null ? 1 : 0

transit_gateway_attachment_id = local.transit_gateway_attachment_id
transit_gateway_route_table_id = var.transit_gateway_route_table_id
}

# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_transit_gateway_route_table_propagation
resource "aws_ec2_transit_gateway_route_table_propagation" "default" {
count = local.transit_gateway_enabled && var.transit_gateway_route_table_id != null ? 1 : 0

transit_gateway_attachment_id = local.transit_gateway_attachment_id
transit_gateway_route_table_id = var.transit_gateway_route_table_id
}

# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_transit_gateway_route
resource "aws_ec2_transit_gateway_route" "default" {
for_each = local.transit_gateway_enabled && var.transit_gateway_route_table_id != null ? var.transit_gateway_routes : {}

blackhole = each.value.blackhole
destination_cidr_block = each.value.destination_cidr_block
transit_gateway_attachment_id = local.transit_gateway_attachment_id
transit_gateway_route_table_id = var.transit_gateway_route_table_id
}
29 changes: 16 additions & 13 deletions outputs.tf
Original file line number Diff line number Diff line change
@@ -1,53 +1,56 @@
output "vpn_gateway_id" {
description = "Virtual Private Gateway ID"
value = join("", aws_vpn_gateway.default.*.id)
value = local.vpn_gateway_id
}

output "customer_gateway_id" {
description = "Customer Gateway ID"
value = join("", aws_customer_gateway.default.*.id)
value = local.customer_gateway_id
}

output "vpn_connection_id" {
description = "VPN Connection ID"
value = join("", aws_vpn_connection.default.*.id)
value = local.vpn_connection_id
}

output "vpn_connection_customer_gateway_configuration" {
description = "The configuration information for the VPN connection's Customer Gateway (in the native XML format)"
value = join(
"",
aws_vpn_connection.default.*.customer_gateway_configuration,
)
sensitive = true
value = join("", aws_vpn_connection.default[*].customer_gateway_configuration)
}

output "vpn_connection_tunnel1_address" {
description = "The public IP address of the first VPN tunnel"
value = join("", aws_vpn_connection.default.*.tunnel1_address)
value = join("", aws_vpn_connection.default[*].tunnel1_address)
}

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

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

output "vpn_connection_tunnel2_address" {
description = "The public IP address of the second VPN tunnel"
value = join("", aws_vpn_connection.default.*.tunnel2_address)
value = join("", aws_vpn_connection.default[*].tunnel2_address)
}

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

output "vpn_connection_tunnel2_vgw_inside_address" {
description = "The RFC 6890 link-local address of the second VPN tunnel (Virtual Private Gateway side)"
value = join("", aws_vpn_connection.default.*.tunnel2_vgw_inside_address)
value = join("", aws_vpn_connection.default[*].tunnel2_vgw_inside_address)
}

output "transit_gateway_attachment_id" {
description = "The ID of the transit gateway attachment for the VPN connection (if a TGW connection)"
value = local.transit_gateway_attachment_id
}

21 changes: 19 additions & 2 deletions variables.tf
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
variable "vpc_id" {
type = string
description = "The ID of the VPC to which the Virtual Private Gateway will be attached"
default = null
}

variable "vpn_gateway_amazon_side_asn" {
Gowiem marked this conversation as resolved.
Show resolved Hide resolved
type = number
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"
default = 64512
}
Expand All @@ -25,9 +27,9 @@ variable "route_table_ids" {
}

variable "vpn_connection_static_routes_only" {
type = string
type = bool
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"
default = "true"
default = false
}

variable "vpn_connection_static_routes_destinations" {
Expand Down Expand Up @@ -191,3 +193,18 @@ variable "transit_gateway_enabled" {
default = false
description = "Set to true to enable VPN connection to transit gateway and then pass in the existing_transit_gateway_id"
}

variable "transit_gateway_route_table_id" {
type = string
default = null
description = "The ID of the route table for the transit gateway that you want to associate + propogate the VPN connection's TGW attachment"
}

variable "transit_gateway_routes" {
type = map(object({
blackhole = optional(bool, false)
destination_cidr_block = string
}))
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."
default = {}
}
6 changes: 1 addition & 5 deletions versions.tf
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
terraform {
required_version = ">= 0.13.0"
required_version = ">= 1.3.0"

required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 2.0"
}
null = {
source = "hashicorp/null"
version = ">= 2.0"
}
}
}
Loading