Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ If you provide explicit EIPs for all zones, no new aws_eip.nat_gateway_eips reso

- Most of the time, except when the instance is actively being replaced, NAT traffic should be routed through the NAT instance and NOT through the NAT Gateway. You can monitor the logs for the text "Failed connectivity tests! Replacing route" to be alerted to NAT instance failures.

- There are four Elastic IP addresses for the NAT instances and four for the NAT Gateways. Be sure to add all eight addresses to any external allow lists if necessary.
- There is always (at least) one Elastic IP address per AZ for the NAT instances and one for each of the NAT Gateways. Be sure to add all addresses to any external allow lists if necessary.

- If you plan on running this in a dual stack network (IPv4 and IPv6), you may notice that it takes ~10 minutes for an alternat node to start. In that case, you can use the `nat_instance_user_data_pre_install` variable to prefer IPv4 over IPv6 before running any user data.

Expand Down
31 changes: 19 additions & 12 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,10 @@ locals {
: {}
)

# Must provide exactly 1 EIP per AZ
# var.nat_instance_eip_ids ignored if doesn't match AZ count
reuse_nat_instance_eips = length(var.nat_instance_eip_ids) == length(var.vpc_az_maps)
nat_instance_eip_ids = local.reuse_nat_instance_eips ? var.nat_instance_eip_ids : (var.prevent_destroy_eips ? aws_eip.protected_nat_instance_eips[*].id : aws_eip.nat_instance_eips[*].id)
nat_instance_eips = var.prevent_destroy_eips ? aws_eip.protected_nat_instance_eips : aws_eip.nat_instance_eips
nat_gateway_eips = var.prevent_destroy_eips ? aws_eip.protected_nat_gateway_eips : aws_eip.nat_gateway_eips
desired_nat_instance_eip_count = length(var.vpc_az_maps) + (var.allow_launch_before_terminating ? 1 : 0)
created_nat_instance_eip_count = var.nat_instance_eip_ids == null ? local.desired_nat_instance_eip_count : 0
created_nat_instance_eip_resources = var.prevent_destroy_eips ? aws_eip.protected_nat_instance_eips : aws_eip.nat_instance_eips
nat_instance_eip_ids = var.nat_instance_eip_ids == null ? local.created_nat_instance_eip_resources[*].id : var.nat_instance_eip_ids

created_ngw_eip_alloc_ids = try({ for az, e in aws_eip.nat_gateway_eips : az => e.id }, {})
protected_ngw_eip_alloc_ids = try({ for az, e in aws_eip.protected_nat_gateway_eips : az => e.id }, {})
Expand All @@ -53,12 +51,11 @@ locals {
local.protected_ngw_eip_alloc_ids,
local.explicit_ngw_eip_alloc_ids
)
created_nat_gateway_eip_resources = var.prevent_destroy_eips ? aws_eip.protected_nat_gateway_eips : aws_eip.nat_gateway_eips
}

resource "aws_eip" "protected_nat_instance_eips" {
count = (local.reuse_nat_instance_eips
? 0
: var.prevent_destroy_eips ? length(var.vpc_az_maps) : 0)
count = var.prevent_destroy_eips ? local.created_nat_instance_eip_count : 0

tags = merge(var.tags, {
"Name" = "alternat-instance-${count.index}"
Expand All @@ -70,9 +67,7 @@ resource "aws_eip" "protected_nat_instance_eips" {
}

resource "aws_eip" "nat_instance_eips" {
count = (local.reuse_nat_instance_eips
? 0
: (var.prevent_destroy_eips ? 0 : length(var.vpc_az_maps)))
count = var.prevent_destroy_eips ? 0 : local.created_nat_instance_eip_count

tags = merge(var.tags, {
"Name" = "alternat-instance-${count.index}"
Expand Down Expand Up @@ -114,6 +109,11 @@ resource "aws_autoscaling_group" "nat_instance" {

health_check_grace_period = var.enable_launch_script_lifecycle_hook ? 0 : 300

instance_maintenance_policy {
min_healthy_percentage = var.allow_launch_before_terminating ? 100 : 0
max_healthy_percentage = var.allow_launch_before_terminating ? 200 : 100
}

dynamic "tag" {
for_each = merge(
var.tags,
Expand All @@ -127,6 +127,13 @@ resource "aws_autoscaling_group" "nat_instance" {
propagate_at_launch = true
}
}

lifecycle {
precondition {
condition = length(local.nat_instance_eip_ids) >= local.desired_nat_instance_eip_count
error_message = "The number of provided NAT instance EIP IDs must be at least ${local.desired_nat_instance_eip_count}."
}
}
}

resource "aws_autoscaling_lifecycle_hook" "nat_instance_launch_script" {
Expand Down
15 changes: 4 additions & 11 deletions outputs.tf
Original file line number Diff line number Diff line change
@@ -1,18 +1,11 @@

output "nat_instance_eips" {
description = "List of Elastic IP addresses used by the NAT instances. This will be empty if EIPs are provided in var.nat_instance_eip_ids."
value = (local.reuse_nat_instance_eips
? []
: local.nat_instance_eips[*].public_ip)
description = "List of Elastic IP addresses created for the NAT instances."
value = [for eip in local.created_nat_instance_eip_resources : eip.public_ip]
}

output "nat_gateway_eips" {
description = "List of Elastic IP addresses used by the standby NAT gateways."
value = [
for eip in local.nat_gateway_eips
: eip.public_ip
if var.create_nat_gateways
]
description = "List of Elastic IP addresses created for the standby NAT gateways."
value = [for eip in local.created_nat_gateway_eip_resources : eip.public_ip]
}

output "nat_instance_security_group_id" {
Expand Down
14 changes: 8 additions & 6 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -164,13 +164,9 @@ variable "nat_instance_type" {
}

variable "nat_instance_eip_ids" {
description = <<-EOT
Allocation IDs of Elastic IPs to associate with the NAT instances. If not specified, EIPs will be created.

Note: if the number of EIPs does not match the number of subnets specified in `vpc_public_subnet_ids`, this variable will be ignored.
EOT
description = "Allocation IDs of Elastic IPs to associate with the NAT instances. If not specified, EIPs will be created."
type = list(string)
default = []
default = null
}

variable "fallback_ngw_eip_allocation_ids" {
Expand Down Expand Up @@ -317,3 +313,9 @@ variable "enable_launch_script_lifecycle_hook" {
type = bool
default = false
}

variable "allow_launch_before_terminating" {
description = "Whether to allow the ASG to launch new instances before terminating others."
type = bool
default = false
}
2 changes: 1 addition & 1 deletion versions.tf
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
terraform {
required_version = ">= 1.1"
required_version = ">= 1.2"

required_providers {
aws = {
Expand Down