From 60cb2cd92b716d7a2873dcbbbe1638e59b2d6d9e Mon Sep 17 00:00:00 2001 From: Mark Madsen Date: Thu, 31 May 2018 14:14:09 -0700 Subject: [PATCH 1/4] Adding Lambda subnets for serverless functions that need to communicate within the VPC --- main.tf | 14 ++++++++++++++ outputs.tf | 11 ++++++++++- variables.tf | 11 +++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/main.tf b/main.tf index c497966d8..93317cb1e 100644 --- a/main.tf +++ b/main.tf @@ -192,6 +192,20 @@ resource "aws_elasticache_subnet_group" "elasticache" { subnet_ids = ["${aws_subnet.elasticache.*.id}"] } +##################### +# Lambdas subnet +##################### +resource "aws_subnet" "lambda" { + count = "${var.create_vpc && length(var.lambda_subnets) > 0 ? length(var.lambda_subnets) : 0}" + + vpc_id = "${aws_vpc.this.id}" + cidr_block = "${var.lambda_subnets[count.index]}" + availability_zone = "${element(var.azs, count.index)}" + + tags = "${merge(var.tags, var.lambda_subnet_tags, map("Name", format("%s-lambda-%s", var.name, element(var.azs, count.index))))}" +} + + ############## # NAT Gateway ############## diff --git a/outputs.tf b/outputs.tf index c6e9269ae..85717d614 100644 --- a/outputs.tf +++ b/outputs.tf @@ -120,6 +120,16 @@ output "elasticache_subnets_cidr_blocks" { value = ["${aws_subnet.elasticache.*.cidr_block}"] } +output "lambda_subnets" { + description = "List of IDs of lambda subnets" + value = ["${aws_subnet.lambda.*.id}"] +} + +output "lambda_subnets_cidr_blocks" { + description = "List of cidr_blocks of lambda subnets" + value = ["${aws_subnet.lambda.*.cidr_block}"] +} + output "elasticache_subnet_group" { description = "ID of elasticache subnet group" value = "${element(concat(aws_elasticache_subnet_group.elasticache.*.id, list("")), 0)}" @@ -249,4 +259,3 @@ output "default_vpc_main_route_table_id" { // description = "The IPv6 CIDR block" // value = "${element(concat(aws_default_vpc.this.*.ipv6_cidr_block, list("")), 0)}" //} - diff --git a/variables.tf b/variables.tf index 67587b8d8..c3fbba0a7 100644 --- a/variables.tf +++ b/variables.tf @@ -46,6 +46,12 @@ variable "elasticache_subnets" { default = [] } +variable "lambda_subnets" { + type = "list" + description = "A list of lambda subnets" + default = [] +} + variable "create_database_subnet_group" { description = "Controls if database subnet group should be created" default = true @@ -177,6 +183,11 @@ variable "elasticache_subnet_tags" { default = {} } +variable "lambda_subnet_tags" { + description = "Additional tags for the lambda subnets" + default = {} +} + variable "dhcp_options_tags" { description = "Additional tags for the DHCP option set" default = {} From 877caa2a75209533ac0d239111d36177db5b7296 Mon Sep 17 00:00:00 2001 From: madsenibis Date: Mon, 4 Jun 2018 08:17:10 -0700 Subject: [PATCH 2/4] Switched to "infra_subnet" for a private subnet without NAT gateway. --- main.tf | 22 ++++++++++++++-------- outputs.tf | 5 +++-- variables.tf | 8 ++++---- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/main.tf b/main.tf index 93317cb1e..80f73ffe4 100644 --- a/main.tf +++ b/main.tf @@ -192,20 +192,19 @@ resource "aws_elasticache_subnet_group" "elasticache" { subnet_ids = ["${aws_subnet.elasticache.*.id}"] } -##################### -# Lambdas subnet -##################### -resource "aws_subnet" "lambda" { - count = "${var.create_vpc && length(var.lambda_subnets) > 0 ? length(var.lambda_subnets) : 0}" +##################################################### +# infra subnets - private subnet with no NAT gateway +##################################################### +resource "aws_subnet" "infra" { + count = "${var.create_vpc && length(var.infra_subnets) > 0 ? length(var.infra_subnets) : 0}" vpc_id = "${aws_vpc.this.id}" - cidr_block = "${var.lambda_subnets[count.index]}" + cidr_block = "${var.infra_subnets[count.index]}" availability_zone = "${element(var.azs, count.index)}" - tags = "${merge(var.tags, var.lambda_subnet_tags, map("Name", format("%s-lambda-%s", var.name, element(var.azs, count.index))))}" + tags = "${merge(var.tags, var.infra_subnet_tags, map("Name", format("%s-infra-%s", var.name, element(var.azs, count.index))))}" } - ############## # NAT Gateway ############## @@ -343,6 +342,13 @@ resource "aws_route_table_association" "elasticache" { route_table_id = "${element(aws_route_table.private.*.id, (var.single_nat_gateway ? 0 : count.index))}" } +resource "aws_route_table_association" "infra" { + count = "${var.create_vpc && length(var.infra_subnets) > 0 ? length(var.infra_subnets) : 0}" + + subnet_id = "${element(aws_subnet.infra.*.id, count.index)}" + route_table_id = "${element(aws_route_table.private.*.id, (var.single_nat_gateway ? 0 : count.index))}" +} + resource "aws_route_table_association" "public" { count = "${var.create_vpc && length(var.public_subnets) > 0 ? length(var.public_subnets) : 0}" diff --git a/outputs.tf b/outputs.tf index 85717d614..2e04efe92 100644 --- a/outputs.tf +++ b/outputs.tf @@ -120,12 +120,12 @@ output "elasticache_subnets_cidr_blocks" { value = ["${aws_subnet.elasticache.*.cidr_block}"] } -output "lambda_subnets" { +output "infra_subnets" { description = "List of IDs of lambda subnets" value = ["${aws_subnet.lambda.*.id}"] } -output "lambda_subnets_cidr_blocks" { +output "infra_subnets_cidr_blocks" { description = "List of cidr_blocks of lambda subnets" value = ["${aws_subnet.lambda.*.cidr_block}"] } @@ -259,3 +259,4 @@ output "default_vpc_main_route_table_id" { // description = "The IPv6 CIDR block" // value = "${element(concat(aws_default_vpc.this.*.ipv6_cidr_block, list("")), 0)}" //} + diff --git a/variables.tf b/variables.tf index c3fbba0a7..74cf6623c 100644 --- a/variables.tf +++ b/variables.tf @@ -46,9 +46,9 @@ variable "elasticache_subnets" { default = [] } -variable "lambda_subnets" { +variable "infra_subnets" { type = "list" - description = "A list of lambda subnets" + description = "A list of infra subnets" default = [] } @@ -183,8 +183,8 @@ variable "elasticache_subnet_tags" { default = {} } -variable "lambda_subnet_tags" { - description = "Additional tags for the lambda subnets" +variable "infra_subnet_tags" { + description = "Additional tags for the infra subnets" default = {} } From 1e71c21006255ffc0bc0e02068c84e310a93ace5 Mon Sep 17 00:00:00 2001 From: madsenibis Date: Mon, 4 Jun 2018 08:22:53 -0700 Subject: [PATCH 3/4] Fixing typo - removing last "lambda" ref. --- outputs.tf | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/outputs.tf b/outputs.tf index 2e04efe92..950f9d66b 100644 --- a/outputs.tf +++ b/outputs.tf @@ -121,13 +121,13 @@ output "elasticache_subnets_cidr_blocks" { } output "infra_subnets" { - description = "List of IDs of lambda subnets" - value = ["${aws_subnet.lambda.*.id}"] + description = "List of IDs of infra subnets" + value = ["${aws_subnet.infra.*.id}"] } output "infra_subnets_cidr_blocks" { - description = "List of cidr_blocks of lambda subnets" - value = ["${aws_subnet.lambda.*.cidr_block}"] + description = "List of cidr_blocks of infra subnets" + value = ["${aws_subnet.infra.*.cidr_block}"] } output "elasticache_subnet_group" { From ff6c156ed79b933a1cc3fe9914fe8b231e26979e Mon Sep 17 00:00:00 2001 From: madsenibis Date: Mon, 4 Jun 2018 09:55:51 -0700 Subject: [PATCH 4/4] Added README docs on intra subnets, and added it to complete VPC example. Fixed naming. --- README.md | 11 ++++++++++- examples/complete-vpc/README.md | 3 ++- examples/complete-vpc/main.tf | 1 + main.tf | 16 ++++++++-------- outputs.tf | 12 ++++++------ variables.tf | 8 ++++---- 6 files changed, 31 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index a5692479d..08fb5409f 100644 --- a/README.md +++ b/README.md @@ -99,13 +99,14 @@ If both `single_nat_gateway` and `one_nat_gateway_per_az` are set to `true`, the ### One NAT Gateway per subnet (default) -By default, the module will determine the number of NAT Gateways to create based on the the `max()` of the private subnet lists (`database_subnets`, `elasticache_subnets`, `private_subnets`, and `redshift_subnets`). For example, if your configuration looks like the following: +By default, the module will determine the number of NAT Gateways to create based on the the `max()` of the private subnet lists (`database_subnets`, `elasticache_subnets`, `private_subnets`, and `redshift_subnets`). The module **does not** take into account the number of `intra_subnets`, since the latter are designed to have no Internet access via NAT Gateway. For example, if your configuration looks like the following: ```hcl database_subnets = ["10.0.21.0/24", "10.0.22.0/24"] elasticache_subnets = ["10.0.31.0/24", "10.0.32.0/24"] private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24", "10.0.4.0/24", "10.0.5.0/24"] redshift_subnets = ["10.0.41.0/24", "10.0.42.0/24"] +intra_subnets = ["10.0.51.0/24", "10.0.52.0/24", "10.0.53.0/24"] ``` Then `5` NAT Gateways will be created since `5` private subnet CIDR blocks were specified. @@ -121,6 +122,10 @@ If `one_nat_gateway_per_az = true` and `single_nat_gateway = false`, then the mo * The variable `var.azs` **must** be specified. * The number of public subnet CIDR blocks specified in `public_subnets` **must** be greater than or equal to the number of availability zones specified in `var.azs`. This is to ensure that each NAT Gateway has a dedicated public subnet to deploy to. +## Private Versus Intra Subnets ## + +By default, if NAT Gateways are enabled, `private` subnets will be configured with routes for Internet traffic that point at the NAT Gateways configured by use of the above options. If you need private subnets that should have no Internet routing (in the sense of RFC1918 Category 1 subnets), `intra_subnets` are available. An example use case is configuration of Lambda functions within a VPC, where the Lambda functions only need to pass traffic to internal resources or VPC endpoints for AWS services. Since Lambda functions allocate Elastic Network Interfaces in proportion to the traffic received, it can be useful to allocate a large private subnet for such allocations, while keeping the traffic they generate entirely internal to the VPC. You can add additional tags with `intra_subnet_tags` as with other subnet types. + ## Conditional creation Sometimes you need to have a way to create VPC resources conditionally but Terraform does not allow to use `count` inside `module` block, so the solution is to specify argument `create_vpc`. @@ -181,6 +186,8 @@ Terraform version 0.10.3 or newer is required for this module to work. | enable_vpn_gateway | Should be true if you want to create a new VPN Gateway resource and attach it to the VPC | string | `false` | no | | external_nat_ip_ids | List of EIP IDs to be assigned to the NAT Gateways (used in combination with reuse_nat_ips) | list | `` | no | | instance_tenancy | A tenancy option for instances launched into the VPC | string | `default` | no | +| intra_subnet_tags | Additional tags for the intra subnets | string | `` | no | +| intra_subnets | A list of intra subnets | list | `` | no | | manage_default_vpc | Should be true to adopt and manage Default VPC | string | `false` | no | | map_public_ip_on_launch | Should be false if you do not want to auto-assign public IP on launch | string | `true` | no | | name | Name to be used on all the resources as identifier | string | `` | no | @@ -225,6 +232,8 @@ Terraform version 0.10.3 or newer is required for this module to work. | elasticache_subnets | List of IDs of elasticache subnets | | elasticache_subnets_cidr_blocks | List of cidr_blocks of elasticache subnets | | igw_id | Internet Gateway | +| intra_subnets | List of IDs of intra subnets | +| intra_subnets_cidr_blocks | List of cidr_blocks of intra subnets | | nat_ids | List of allocation ID of Elastic IPs created for AWS NAT Gateway | | nat_public_ips | List of public Elastic IPs created for AWS NAT Gateway | | natgw_ids | List of NAT Gateway IDs | diff --git a/examples/complete-vpc/README.md b/examples/complete-vpc/README.md index 3a5397480..dddba26bc 100644 --- a/examples/complete-vpc/README.md +++ b/examples/complete-vpc/README.md @@ -2,7 +2,7 @@ Configuration in this directory creates set of VPC resources which may be sufficient for staging or production environment (look into [simple-vpc](../simple-vpc) for more simplified setup). -There are public, private, database, ElastiCache subnets, NAT Gateways created in each availability zone. +There are public, private, database, ElastiCache subnets, intra (private w/o Internet access) subnets, and NAT Gateways created in each availability zone. ## Usage @@ -28,6 +28,7 @@ Note that this example may create resources which can cost money (AWS Elastic IP | private_subnets | Subnets | | public_subnets | List of IDs of public subnets | | redshift_subnets | List of IDs of redshift subnets | +| intra_subnets | List of IDs of intra subnets | | vpc_id | VPC | diff --git a/examples/complete-vpc/main.tf b/examples/complete-vpc/main.tf index 2b65875c2..f4b6c519d 100644 --- a/examples/complete-vpc/main.tf +++ b/examples/complete-vpc/main.tf @@ -15,6 +15,7 @@ module "vpc" { database_subnets = ["10.10.21.0/24", "10.10.22.0/24", "10.10.23.0/24"] elasticache_subnets = ["10.10.31.0/24", "10.10.32.0/24", "10.10.33.0/24"] redshift_subnets = ["10.10.41.0/24", "10.10.42.0/24", "10.10.43.0/24"] + intra_subnets = ["10.10.51.0/24", "10.10.52.0/24", "10.10.53.0/24"] create_database_subnet_group = false diff --git a/main.tf b/main.tf index 80f73ffe4..fc41fdaa4 100644 --- a/main.tf +++ b/main.tf @@ -193,16 +193,16 @@ resource "aws_elasticache_subnet_group" "elasticache" { } ##################################################### -# infra subnets - private subnet with no NAT gateway +# intra subnets - private subnet with no NAT gateway ##################################################### -resource "aws_subnet" "infra" { - count = "${var.create_vpc && length(var.infra_subnets) > 0 ? length(var.infra_subnets) : 0}" +resource "aws_subnet" "intra" { + count = "${var.create_vpc && length(var.intra_subnets) > 0 ? length(var.intra_subnets) : 0}" vpc_id = "${aws_vpc.this.id}" - cidr_block = "${var.infra_subnets[count.index]}" + cidr_block = "${var.intra_subnets[count.index]}" availability_zone = "${element(var.azs, count.index)}" - tags = "${merge(var.tags, var.infra_subnet_tags, map("Name", format("%s-infra-%s", var.name, element(var.azs, count.index))))}" + tags = "${merge(var.tags, var.intra_subnet_tags, map("Name", format("%s-intra-%s", var.name, element(var.azs, count.index))))}" } ############## @@ -342,10 +342,10 @@ resource "aws_route_table_association" "elasticache" { route_table_id = "${element(aws_route_table.private.*.id, (var.single_nat_gateway ? 0 : count.index))}" } -resource "aws_route_table_association" "infra" { - count = "${var.create_vpc && length(var.infra_subnets) > 0 ? length(var.infra_subnets) : 0}" +resource "aws_route_table_association" "intra" { + count = "${var.create_vpc && length(var.intra_subnets) > 0 ? length(var.intra_subnets) : 0}" - subnet_id = "${element(aws_subnet.infra.*.id, count.index)}" + subnet_id = "${element(aws_subnet.intra.*.id, count.index)}" route_table_id = "${element(aws_route_table.private.*.id, (var.single_nat_gateway ? 0 : count.index))}" } diff --git a/outputs.tf b/outputs.tf index 950f9d66b..4e71f12bb 100644 --- a/outputs.tf +++ b/outputs.tf @@ -120,14 +120,14 @@ output "elasticache_subnets_cidr_blocks" { value = ["${aws_subnet.elasticache.*.cidr_block}"] } -output "infra_subnets" { - description = "List of IDs of infra subnets" - value = ["${aws_subnet.infra.*.id}"] +output "intra_subnets" { + description = "List of IDs of intra subnets" + value = ["${aws_subnet.intra.*.id}"] } -output "infra_subnets_cidr_blocks" { - description = "List of cidr_blocks of infra subnets" - value = ["${aws_subnet.infra.*.cidr_block}"] +output "intra_subnets_cidr_blocks" { + description = "List of cidr_blocks of intra subnets" + value = ["${aws_subnet.intra.*.cidr_block}"] } output "elasticache_subnet_group" { diff --git a/variables.tf b/variables.tf index 74cf6623c..0098c353f 100644 --- a/variables.tf +++ b/variables.tf @@ -46,9 +46,9 @@ variable "elasticache_subnets" { default = [] } -variable "infra_subnets" { +variable "intra_subnets" { type = "list" - description = "A list of infra subnets" + description = "A list of intra subnets" default = [] } @@ -183,8 +183,8 @@ variable "elasticache_subnet_tags" { default = {} } -variable "infra_subnet_tags" { - description = "Additional tags for the infra subnets" +variable "intra_subnet_tags" { + description = "Additional tags for the intra subnets" default = {} }