Skip to content

Commit 0fad71f

Browse files
authored
Multi az nat gateways (#29)
* Use one nat gateway per availability zone
1 parent 368b05e commit 0fad71f

File tree

6 files changed

+42
-47
lines changed

6 files changed

+42
-47
lines changed

README.md

+6-6
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ This module creates the following resources in AWS:
2222
- 2 or more private subnets in different AZ
2323
- an internet gateway
2424
- route tables
25+
- a NAT gateway in each public subnet
2526

26-
In addition, if NAT gateway is enabled:
27+
In addition, if NAT gateways are not provided an EIP allocation id:
2728

28-
- an Elastic IP (optional)
29-
- a NAT gateway in one of the public subnets
29+
- an Elastic IP for each such NAT gateway
3030

3131
## Usage example
3232

@@ -59,10 +59,10 @@ module "network" {
5959
}
6060
}
6161
nat_gateway = {
62-
name = "quortex"
63-
subnet_key = "pub-eu-west-1b"
62+
quortex = {
63+
subnet_key = "pub-eu-west-1b"
64+
}
6465
}
65-
nat_eip_allocation_id = "" # set an existing EIP's id, or an empty string to create a new EIP
6666
}
6767
6868
```

locals.tf

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
locals {
2-
public_subnets = { for k, v in aws_subnet.quortex : k => v if v.map_public_ip_on_launch == true }
3-
private_subnets = { for k, v in aws_subnet.quortex : k => v if v.map_public_ip_on_launch == false }
4-
enable_nat_gateway = var.nat_gateway != null
2+
public_subnets = { for k, v in aws_subnet.quortex : k => v if v.map_public_ip_on_launch == true }
3+
private_subnets = { for k, v in aws_subnet.quortex : k => v if v.map_public_ip_on_launch == false }
4+
zoned_gateway_ids = { for k, v in local.public_subnets : v.availability_zone => [for gw in values(aws_nat_gateway.quortex) : gw.id if gw.subnet_id == v.id][0] }
55
}

main.tf

+3-3
Original file line numberDiff line numberDiff line change
@@ -120,17 +120,17 @@ resource "aws_route_table" "quortex_private" {
120120

121121
# Route to the NAT, if NAT is enabled...
122122
dynamic "route" {
123-
for_each = local.enable_nat_gateway ? [1] : []
123+
for_each = local.zoned_gateway_ids[each.value.availability_zone] != null ? [1] : []
124124

125125
content {
126126
cidr_block = "0.0.0.0/0"
127-
nat_gateway_id = aws_nat_gateway.quortex[0].id
127+
nat_gateway_id = local.zoned_gateway_ids[each.value.availability_zone]
128128
}
129129
}
130130

131131
# ...otherwise, route to the Internet Gateway
132132
dynamic "route" {
133-
for_each = local.enable_nat_gateway ? [] : [1]
133+
for_each = local.zoned_gateway_ids[each.value.availability_zone] == null ? [1] : []
134134

135135
content {
136136
cidr_block = "0.0.0.0/0"

nat_gateway.tf

+14-13
Original file line numberDiff line numberDiff line change
@@ -16,30 +16,31 @@
1616

1717

1818
# A static Elastic IP used for Quortex cluster External NAT Gateway IP.
19-
# This resource is created only if no existing EIP is specified.
19+
# This resource is created for each nat gateway where no existing EIP is specified.
2020
resource "aws_eip" "quortex" {
21-
count = (local.enable_nat_gateway && var.nat_eip_allocation_id == "") ? 1 : 0
21+
for_each = { for k, v in var.nat_gateways : k => v if v.eip_allocation_id == null }
2222

23-
tags = merge({ "Name" = var.eip_name }, var.tags)
23+
tags = merge({ "Name" = "${var.nat_gateway_name_prefix}${each.key}" }, var.tags)
2424
}
2525

26-
# An existing Elastic IP that will be attached to the NAT gateway
27-
# This datasource is used only to display the IP address
26+
# An existing Elastic IP that will be attached to NAT gateways when
27+
# the id is defined. This datasource is used only to display the IP address
2828
data "aws_eip" "existing_eip" {
29-
count = (local.enable_nat_gateway && var.nat_eip_allocation_id != "") ? 1 : 0
29+
for_each = { for k, v in var.nat_gateways : k => v if v.eip_allocation_id != null }
3030

31-
id = var.nat_eip_allocation_id
31+
id = each.value.eip_allocation_id
3232
}
3333

34-
# A single NAT gateway is used for all subnets (NAT gateway is placed in the 1st subnet),
35-
# or, one NAT gateway in each subnet
34+
# Nat gateways depending on the list passed in the nat_gateways variable
3635
resource "aws_nat_gateway" "quortex" {
37-
count = local.enable_nat_gateway ? 1 : 0
36+
for_each = { for k, v in var.nat_gateways : k => v if local.public_subnets[v.subnet_key] != null }
3837

39-
allocation_id = var.nat_eip_allocation_id == "" ? aws_eip.quortex[0].id : data.aws_eip.existing_eip[0].id
40-
subnet_id = aws_subnet.quortex[var.nat_gateway.subnet_key].id
38+
allocation_id = each.value.eip_allocation_id == null ? aws_eip.quortex[each.key].id : data.aws_eip.existing_eip[each.key].id
39+
subnet_id = local.public_subnets[each.value.subnet_key].id
4140

42-
tags = merge({ "Name" = var.nat_gateway.name }, var.tags)
41+
tags = merge({
42+
"Name" = "${var.nat_gateway_name_prefix}${each.key}"
43+
}, var.tags)
4344

4445
depends_on = [aws_internet_gateway.quortex]
4546
}

outputs.tf

+6-6
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,12 @@ output "route_table_ids_private" {
5050
description = "The IDs of the route tables for private subnets"
5151
}
5252

53-
output "nat_eip_id" {
54-
value = try(local.enable_nat_gateway ? (var.nat_eip_allocation_id == "" ? aws_eip.quortex[0].id : var.nat_eip_allocation_id) : "", "")
55-
description = "The ID of the Elastic IP associated to the Quortex cluster External NAT Gateway IP."
53+
output "nat_eip_ids" {
54+
value = concat(values(aws_eip.quortex)[*].allocation_id, [for k, v in var.nat_gateways : v.eip_allocation_id if v.eip_allocation_id != null])
55+
description = "The IDs of the Elastic IPs associated to the Quortex cluster External NAT Gateways."
5656
}
5757

58-
output "nat_eip_address" {
59-
value = try(local.enable_nat_gateway ? (var.nat_eip_allocation_id == "" ? aws_eip.quortex[0].public_ip : data.aws_eip.existing_eip[0].public_ip) : "", "")
60-
description = "The public address of the Elastic IP associated to the Quortex cluster External NAT Gateway IP."
58+
output "nat_eip_addresses" {
59+
value = concat(values(aws_eip.quortex)[*].public_ip, values(data.aws_eip.existing_eip)[*].public_ip)
60+
description = "The public addresses of the Elastic IP associated to the Quortex cluster External NAT Gateways."
6161
}

variables.tf

+10-16
Original file line numberDiff line numberDiff line change
@@ -49,21 +49,21 @@ variable "route_table_prefix" {
4949
default = "quortex-"
5050
}
5151

52-
variable "nat_gateway" {
53-
type = object({ name = string, subnet_key = string })
52+
variable "nat_gateway_name_prefix" {
53+
type = string
54+
description = "A prefix for the name of the NAT Gateways."
55+
default = "quortex-"
56+
}
57+
58+
variable "nat_gateways" {
59+
type = map(object({ subnet_key = string, eip_allocation_id = optional(string) }))
5460
description = <<EOT
55-
The NAT gateway configuration, a name and a subnet_key that must match a key
56-
of the given subnets variable.
61+
The NAT gateways configuration, a map of object, each with a subnet_key that must
62+
match a key of the given subnets variable and an optional eip allocation id.
5763
EOT
5864
default = null
5965
}
6066

61-
variable "eip_name" {
62-
type = string
63-
description = "Name for the Elastic IP resource"
64-
default = "quortex"
65-
}
66-
6767
variable "vpc_cidr_block" {
6868
type = string
6969
description = "The CIDR block for the VPC"
@@ -96,9 +96,3 @@ variable "tags" {
9696
description = "The tags (a map of key/value pairs) to be applied to created resources."
9797
default = {}
9898
}
99-
100-
variable "nat_eip_allocation_id" {
101-
type = string
102-
description = "Allocation ID of an existing EIP that should be associated to the NAT gateway. Specify this ID if you want to associate an existing EIP to the NAT gateway. If not specified, a new EIP will be created and associated to the NAT gateway."
103-
default = ""
104-
}

0 commit comments

Comments
 (0)