diff --git a/README.md b/README.md index 65e6c7e57..4bfea1fb4 100644 --- a/README.md +++ b/README.md @@ -9,11 +9,11 @@ These types of resources are supported: * [Subnet](https://www.terraform.io/docs/providers/aws/r/subnet.html) * [Route](https://www.terraform.io/docs/providers/aws/r/route.html) * [Route table](https://www.terraform.io/docs/providers/aws/r/route_table.html) -* [Internet Gateway](https://www.terraform.io/docs/providers/aws/r/internet_gateway.html) +* [Internet Gateway](https://www.terraform.io/docs/providers/aws/r/internet_gateway.html) * [NAT Gateway](https://www.terraform.io/docs/providers/aws/r/nat_gateway.html) * [VPN Gateway](https://www.terraform.io/docs/providers/aws/r/vpn_gateway.html) * [VPC Endpoint](https://www.terraform.io/docs/providers/aws/r/vpc_endpoint.html) (S3 and DynamoDB) -* [RDS DB Subnet Group](https://www.terraform.io/docs/providers/aws/r/db_subnet_group.html) +* [RDS DB Subnet Group](https://www.terraform.io/docs/providers/aws/r/db_subnet_group.html) * [ElastiCache Subnet Group](https://www.terraform.io/docs/providers/aws/r/elasticache_subnet_group.html) * [DHCP Options Set](https://www.terraform.io/docs/providers/aws/r/vpc_dhcp_options.html) @@ -31,7 +31,7 @@ module "vpc" { name = "my-vpc" cidr = "10.0.0.0/16" - + azs = ["eu-west-1a", "eu-west-1b", "eu-west-1c"] private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"] public_subnets = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"] @@ -46,10 +46,45 @@ module "vpc" { } ``` +External NAT Gateway IPs +------------------------ + +By default this module will provision new Elastic IPs for the VPC's NAT Gateways. +This means that when creating a new VPC, new IPs are allocated, and when that VPC is destroyed those IPs are released. +Sometimes it is handy to keep the same IPs even after the VPC is destroyed and re-created. +To that end, it is possible to assign existing IPs to the NAT Gateways. +This prevents the destruction of the VPC from releasing those IPs, while making it possible that a re-created VPC uses the same IPs. + +To achieve this, allocate the IPs outside the VPC module declaration. +```hcl +resource "aws_eip" "nat" { + count = 3 + + vpc = true +} +``` + +Then, pass the allocated IPs as a parameter to this module. +```hcl +module "vpc" { + source = "terraform-aws-modules/vpc/aws" + + # The rest of arguments are omitted for brevity + + enable_nat_gateway = true + single_nat_gateway = false + external_nat_ip_ids = ["${resource.aws_eip.nat.*.id}"] # <= IPs specified here as input to the module +} +``` + +Note that in the example we allocate 3 IPs because we will be provisioning 3 NAT Gateways (due to `single_nat_gateway = false` and having 3 subnets). +If, on the other hand, `single_nat_gateway = true`, then `aws_eip.nat` would only need to allocate 1 IP. +Passing the IPs into the module is done by setting variable `external_nat_ip_ids = ["${resource.aws_eip.nat.*.id}"]`. + Terraform version ----------------- -Terraform version 1.0.0 or newer is required for this version to work. +Terraform version 0.10.13 or newer is required for this module to work. Examples -------- @@ -66,4 +101,4 @@ Module managed by [Anton Babenko](https://github.com/antonbabenko). License ------- -Apache 2 Licensed. See LICENSE for full details. \ No newline at end of file +Apache 2 Licensed. See LICENSE for full details. diff --git a/main.tf b/main.tf index 6a8a9c942..fa3ac9f3a 100644 --- a/main.tf +++ b/main.tf @@ -1,3 +1,7 @@ +terraform { + required_version = ">= 0.10.13" # introduction of Local Values configuration language feature +} + ###### # VPC ###### @@ -152,8 +156,20 @@ resource "aws_elasticache_subnet_group" "elasticache" { ############## # NAT Gateway ############## +# Workaround for interpolation not being able to "short-circuit" the evaluation of the conditional branch that doesn't end up being used +# Source: https://github.com/hashicorp/terraform/issues/11566#issuecomment-289417805 +# +# The logical expression would be +# +# nat_gateway_ips = var.reuse_nat_ips ? var.external_nat_ip_ids : aws_eip.nat.*.id +# +# but then when count of aws_eip.nat.*.id is zero, this would throw a resource not found error on aws_eip.nat.*.id. +locals { + nat_gateway_ips = "${split(",", (var.reuse_nat_ips ? join(",", var.external_nat_ip_ids) : join(",", aws_eip.nat.*.id)))}" +} + resource "aws_eip" "nat" { - count = "${var.enable_nat_gateway ? (var.single_nat_gateway ? 1 : length(var.azs)) : 0}" + count = "${(var.enable_nat_gateway && !var.reuse_nat_ips) ? (var.single_nat_gateway ? 1 : length(var.azs)) : 0}" vpc = true } @@ -161,7 +177,7 @@ resource "aws_eip" "nat" { resource "aws_nat_gateway" "this" { count = "${var.enable_nat_gateway ? (var.single_nat_gateway ? 1 : length(var.azs)) : 0}" - allocation_id = "${element(aws_eip.nat.*.id, (var.single_nat_gateway ? 0 : count.index))}" + allocation_id = "${element(local.nat_gateway_ips, (var.single_nat_gateway ? 0 : count.index))}" subnet_id = "${element(aws_subnet.public.*.id, (var.single_nat_gateway ? 0 : count.index))}" tags = "${merge(var.tags, map("Name", format("%s-%s", var.name, element(var.azs, (var.single_nat_gateway ? 0 : count.index)))))}" diff --git a/variables.tf b/variables.tf index b3ca52a68..7148bb839 100644 --- a/variables.tf +++ b/variables.tf @@ -65,6 +65,17 @@ variable "single_nat_gateway" { default = false } +variable "reuse_nat_ips" { + description = "Should be true if you don't want EIPs to be created for your NAT Gateways and will instead pass them in via the 'external_nat_ip_ids' variable" + default = false +} + +variable "external_nat_ip_ids" { + description = "List of EIP IDs to be assigned to the NAT Gateways (used in combination with reuse_nat_ips)" + type = "list" + default = [] +} + variable "enable_dynamodb_endpoint" { description = "Should be true if you want to provision a DynamoDB endpoint to the VPC" default = false