Skip to content

Commit

Permalink
Add ipv6 support (#55)
Browse files Browse the repository at this point in the history
* Add ipv6 support

* Auto Format

* Update examples/complete/variables.tf

Co-authored-by: Andriy Knysh <aknysh@users.noreply.github.com>

* Fix output, update test, and remove data block

* Auto Format

* test private networks still work

* Ignore terraform lock file in the test dir

* Update .gitignore

Co-authored-by: cloudpossebot <11232728+cloudpossebot@users.noreply.github.com>
Co-authored-by: Andriy Knysh <aknysh@users.noreply.github.com>
  • Loading branch information
3 people authored Apr 8, 2022
1 parent b2edab8 commit 9c5ef29
Show file tree
Hide file tree
Showing 11 changed files with 75 additions and 17 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ Available targets:
| [aws_network_acl.public](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/network_acl) | resource |
| [aws_route.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route) | resource |
| [aws_route.public](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route) | resource |
| [aws_route.public_ipv6](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route) | resource |
| [aws_route_table.private](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table) | resource |
| [aws_route_table.public](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table) | resource |
| [aws_route_table_association.private](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association) | resource |
Expand All @@ -317,6 +318,8 @@ Available targets:
| <a name="input_environment"></a> [environment](#input\_environment) | ID element. Usually used for region e.g. 'uw2', 'us-west-2', OR role 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no |
| <a name="input_id_length_limit"></a> [id\_length\_limit](#input\_id\_length\_limit) | Limit `id` to this many characters (minimum 6).<br>Set to `0` for unlimited length.<br>Set to `null` for keep the existing setting, which defaults to `0`.<br>Does not affect `id_full`. | `number` | `null` | no |
| <a name="input_igw_id"></a> [igw\_id](#input\_igw\_id) | Internet Gateway ID that is used as a default route when creating public subnets (e.g. `igw-9c26a123`) | `string` | `""` | no |
| <a name="input_ipv6_cidr_block"></a> [ipv6\_cidr\_block](#input\_ipv6\_cidr\_block) | Base IPv6 CIDR block which is divided into /64 subnet CIDR blocks | `string` | `null` | no |
| <a name="input_ipv6_enabled"></a> [ipv6\_enabled](#input\_ipv6\_enabled) | Flag to enable/disable IPv6 creation in public subnets | `bool` | `false` | no |
| <a name="input_label_key_case"></a> [label\_key\_case](#input\_label\_key\_case) | Controls the letter case of the `tags` keys (label names) for tags generated by this module.<br>Does not affect keys of tags passed in via the `tags` input.<br>Possible values: `lower`, `title`, `upper`.<br>Default value: `title`. | `string` | `null` | no |
| <a name="input_label_order"></a> [label\_order](#input\_label\_order) | The order in which the labels (ID elements) appear in the `id`.<br>Defaults to ["namespace", "environment", "stage", "name", "attributes"].<br>You can omit any of the 6 labels ("tenant" is the 6th), but at least one must be present. | `list(string)` | `null` | no |
| <a name="input_label_value_case"></a> [label\_value\_case](#input\_label\_value\_case) | Controls the letter case of ID elements (labels) as included in `id`,<br>set as tag values, and output by this module individually.<br>Does not affect values of tags passed in via the `tags` input.<br>Possible values: `lower`, `title`, `upper` and `none` (no transformation).<br>Set this to `title` and set `delimiter` to `""` to yield Pascal Case IDs.<br>Default value: `lower`. | `string` | `null` | no |
Expand Down Expand Up @@ -347,6 +350,7 @@ Available targets:
| <a name="output_az_subnet_arns"></a> [az\_subnet\_arns](#output\_az\_subnet\_arns) | Map of AZ names to subnet ARNs |
| <a name="output_az_subnet_cidr_blocks"></a> [az\_subnet\_cidr\_blocks](#output\_az\_subnet\_cidr\_blocks) | Map of AZ names to subnet CIDR blocks |
| <a name="output_az_subnet_ids"></a> [az\_subnet\_ids](#output\_az\_subnet\_ids) | Map of AZ names to subnet IDs |
| <a name="output_az_subnet_ipv6_cidr_blocks"></a> [az\_subnet\_ipv6\_cidr\_blocks](#output\_az\_subnet\_ipv6\_cidr\_blocks) | Map of AZ names to subnet IPv6 CIDR blocks |
| <a name="output_az_subnet_map"></a> [az\_subnet\_map](#output\_az\_subnet\_map) | Map of AZ names to map of information about subnets |
<!-- markdownlint-restore -->

Expand Down
4 changes: 4 additions & 0 deletions docs/terraform.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
| [aws_network_acl.public](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/network_acl) | resource |
| [aws_route.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route) | resource |
| [aws_route.public](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route) | resource |
| [aws_route.public_ipv6](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route) | resource |
| [aws_route_table.private](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table) | resource |
| [aws_route_table.public](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table) | resource |
| [aws_route_table_association.private](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association) | resource |
Expand All @@ -55,6 +56,8 @@
| <a name="input_environment"></a> [environment](#input\_environment) | ID element. Usually used for region e.g. 'uw2', 'us-west-2', OR role 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no |
| <a name="input_id_length_limit"></a> [id\_length\_limit](#input\_id\_length\_limit) | Limit `id` to this many characters (minimum 6).<br>Set to `0` for unlimited length.<br>Set to `null` for keep the existing setting, which defaults to `0`.<br>Does not affect `id_full`. | `number` | `null` | no |
| <a name="input_igw_id"></a> [igw\_id](#input\_igw\_id) | Internet Gateway ID that is used as a default route when creating public subnets (e.g. `igw-9c26a123`) | `string` | `""` | no |
| <a name="input_ipv6_cidr_block"></a> [ipv6\_cidr\_block](#input\_ipv6\_cidr\_block) | Base IPv6 CIDR block which is divided into /64 subnet CIDR blocks | `string` | `null` | no |
| <a name="input_ipv6_enabled"></a> [ipv6\_enabled](#input\_ipv6\_enabled) | Flag to enable/disable IPv6 creation in public subnets | `bool` | `false` | no |
| <a name="input_label_key_case"></a> [label\_key\_case](#input\_label\_key\_case) | Controls the letter case of the `tags` keys (label names) for tags generated by this module.<br>Does not affect keys of tags passed in via the `tags` input.<br>Possible values: `lower`, `title`, `upper`.<br>Default value: `title`. | `string` | `null` | no |
| <a name="input_label_order"></a> [label\_order](#input\_label\_order) | The order in which the labels (ID elements) appear in the `id`.<br>Defaults to ["namespace", "environment", "stage", "name", "attributes"].<br>You can omit any of the 6 labels ("tenant" is the 6th), but at least one must be present. | `list(string)` | `null` | no |
| <a name="input_label_value_case"></a> [label\_value\_case](#input\_label\_value\_case) | Controls the letter case of ID elements (labels) as included in `id`,<br>set as tag values, and output by this module individually.<br>Does not affect values of tags passed in via the `tags` input.<br>Possible values: `lower`, `title`, `upper` and `none` (no transformation).<br>Set this to `title` and set `delimiter` to `""` to yield Pascal Case IDs.<br>Default value: `lower`. | `string` | `null` | no |
Expand Down Expand Up @@ -85,5 +88,6 @@
| <a name="output_az_subnet_arns"></a> [az\_subnet\_arns](#output\_az\_subnet\_arns) | Map of AZ names to subnet ARNs |
| <a name="output_az_subnet_cidr_blocks"></a> [az\_subnet\_cidr\_blocks](#output\_az\_subnet\_cidr\_blocks) | Map of AZ names to subnet CIDR blocks |
| <a name="output_az_subnet_ids"></a> [az\_subnet\_ids](#output\_az\_subnet\_ids) | Map of AZ names to subnet IDs |
| <a name="output_az_subnet_ipv6_cidr_blocks"></a> [az\_subnet\_ipv6\_cidr\_blocks](#output\_az\_subnet\_ipv6\_cidr\_blocks) | Map of AZ names to subnet IPv6 CIDR blocks |
| <a name="output_az_subnet_map"></a> [az\_subnet\_map](#output\_az\_subnet\_map) | Map of AZ names to map of information about subnets |
<!-- markdownlint-restore -->
4 changes: 3 additions & 1 deletion examples/complete/fixtures.us-east-2.tfvars
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ name = "multi-az-subnets"

availability_zones = ["us-east-2a", "us-east-2b", "us-east-2c"]

cidr_block = "172.16.0.0/16"
cidr_block = "172.16.0.0/16"

ipv6_enabled = true
24 changes: 17 additions & 7 deletions examples/complete/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,24 @@ provider "aws" {
}

locals {
public_cidr_block = cidrsubnet(var.cidr_block, 2, 0)
public_only_cidr_block = cidrsubnet(var.cidr_block, 2, 1)
private_cidr_block = cidrsubnet(var.cidr_block, 2, 2)
private_only_cidr_block = cidrsubnet(var.cidr_block, 2, 3)
public_cidr_block = cidrsubnet(var.cidr_block, 2, 0)
public_only_cidr_block = cidrsubnet(var.cidr_block, 2, 1)
private_cidr_block = cidrsubnet(var.cidr_block, 2, 2)
private_only_cidr_block = cidrsubnet(var.cidr_block, 2, 3)
public_ipv6_cidr_block = module.this.enabled ? cidrsubnet(module.vpc.ipv6_cidr_block, 2, 0) : ""
public_only_ipv6_cidr_block = module.this.enabled ? cidrsubnet(module.vpc.ipv6_cidr_block, 2, 1) : ""

}

module "vpc" {
source = "cloudposse/vpc/aws"
version = "0.21.1"
version = "0.27.0"

cidr_block = var.cidr_block
cidr_block = var.cidr_block
assign_generated_ipv6_cidr_block = true

context = module.this.context

}

module "public_subnets" {
Expand All @@ -27,6 +32,8 @@ module "public_subnets" {
type = "public"
igw_id = module.vpc.igw_id
nat_gateway_enabled = true
ipv6_enabled = var.ipv6_enabled
ipv6_cidr_block = local.public_ipv6_cidr_block

context = module.this.context
}
Expand All @@ -40,6 +47,8 @@ module "public_only_subnets" {
type = "public"
igw_id = module.vpc.igw_id
nat_gateway_enabled = false
ipv6_enabled = var.ipv6_enabled
ipv6_cidr_block = local.public_only_ipv6_cidr_block

context = module.this.context
}
Expand All @@ -51,6 +60,7 @@ module "private_subnets" {
vpc_id = module.vpc.vpc_id
cidr_block = local.private_cidr_block
type = "private"
ipv6_enabled = var.ipv6_enabled

# Map of AZ names to NAT Gateway IDs that was created in "public_subnets" module
az_ngw_ids = module.public_subnets.az_ngw_ids
Expand All @@ -65,10 +75,10 @@ module "private_only_subnets" {
vpc_id = module.vpc.vpc_id
cidr_block = local.private_only_cidr_block
type = "private"
ipv6_enabled = false

# No NAT gateways supplied, should create subnets with empty route tables
# az_ngw_ids = module.public_subnets.az_ngw_ids

context = module.this.context
}

6 changes: 5 additions & 1 deletion examples/complete/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,8 @@ output "private_az_subnet_cidr_blocks" {

output "public_az_subnet_cidr_blocks" {
value = module.public_subnets.az_subnet_cidr_blocks
}
}

output "public_az_subnet_ipv6_cidr_blocks" {
value = module.public_subnets.az_subnet_ipv6_cidr_blocks
}
5 changes: 5 additions & 0 deletions examples/complete/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,8 @@ variable "availability_zones" {
type = list(string)
description = "List of Availability Zones (e.g. `['us-east-1a', 'us-east-1b', 'us-east-1c']`)"
}

variable "ipv6_enabled" {
description = "Flag to enable/disable IPv6 creation in public subnets"
type = bool
}
2 changes: 2 additions & 0 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ locals {
subnet_cidr_block = local.public_enabled ? aws_subnet.public[az].cidr_block : aws_subnet.private[az].cidr_block
route_table_id = local.public_enabled ? aws_route_table.public[az].id : aws_route_table.private[az].id
ngw_id = local.public_enabled && var.nat_gateway_enabled ? aws_nat_gateway.public[az].id : null

subnet_ipv6_cidr_block = local.public_ipv6_enabled ? aws_subnet.public[az].ipv6_cidr_block : null
}
}
}
5 changes: 5 additions & 0 deletions outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ output "az_subnet_cidr_blocks" {
description = "Map of AZ names to subnet CIDR blocks"
}

output "az_subnet_ipv6_cidr_blocks" {
value = { for az, m in local.output_map : az => m.subnet_ipv6_cidr_block }
description = "Map of AZ names to subnet IPv6 CIDR blocks"
}

output "az_route_table_ids" {
value = { for az, m in local.output_map : az => m.route_table_id }
description = " Map of AZ names to Route Table IDs"
Expand Down
19 changes: 17 additions & 2 deletions public.tf
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
locals {
public_azs = local.public_enabled ? { for idx, az in var.availability_zones : az => idx } : {}
public_nat_gateway_azs = local.public_enabled && var.nat_gateway_enabled ? local.public_azs : {}
public_azs = local.public_enabled ? { for idx, az in var.availability_zones : az => idx } : {}
public_nat_gateway_azs = local.public_enabled && var.nat_gateway_enabled ? local.public_azs : {}
public_ipv6_enabled = local.public_enabled && var.ipv6_enabled
public_ipv6_azs = local.public_ipv6_enabled ? local.public_azs : {}
public_ipv6_target_mask = 64
}

module "public_label" {
Expand All @@ -18,6 +21,9 @@ resource "aws_subnet" "public" {
vpc_id = var.vpc_id
availability_zone = each.key
cidr_block = cidrsubnet(var.cidr_block, ceil(log(var.max_subnets, 2)), each.value)
ipv6_cidr_block = local.public_ipv6_enabled ? cidrsubnet(var.ipv6_cidr_block, (
local.public_ipv6_target_mask - tonumber(split("/", var.ipv6_cidr_block)[1])
), each.value) : null

tags = merge(
module.public_label.tags,
Expand Down Expand Up @@ -88,6 +94,15 @@ resource "aws_route" "public" {
depends_on = [aws_route_table.public]
}

resource "aws_route" "public_ipv6" {
for_each = local.public_ipv6_azs

route_table_id = aws_route_table.public[each.key].id
gateway_id = var.igw_id
destination_ipv6_cidr_block = "::/0"
depends_on = [aws_route_table.public]
}

resource "aws_route_table_association" "public" {
for_each = local.public_azs

Expand Down
8 changes: 2 additions & 6 deletions test/src/examples_complete_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,15 +94,10 @@ func TestExamplesComplete(t *testing.T) {

// Run `terraform output` to get the value of an output variable
privateSubnetIds := terraform.OutputMap(t, terraformOptions, "private_az_subnet_ids")
// Run `terraform output` to get the value of an output variable
privateRouteTableIds := terraform.OutputMap(t, terraformOptions, "private_az_route_table_ids")
// Run `terraform output` to get the value of an output variable
publicNATGateWayIds := terraform.OutputMap(t, terraformOptions, "public_az_ngw_ids")
// Run `terraform output` to get the value of an output variable
publicOnlyNATGateWayIds := terraform.OutputMap(t, terraformOptions, "public_only_az_ngw_ids")
// Run `terraform output` to get the value of an output variable
publicRouteTableIds := terraform.OutputMap(t, terraformOptions, "public_az_route_table_ids")
// Run `terraform output` to get the value of an output variable
publicSubnetIds := terraform.OutputMap(t, terraformOptions, "public_az_subnet_ids")

expectedAZs := []string{"us-east-2a", "us-east-2b", "us-east-2c"}
Expand Down Expand Up @@ -146,7 +141,6 @@ func TestExamplesCompleteDisabledModule(t *testing.T) {
Vars: map[string]interface{}{
"enabled": "false",
},

}

// At the end of the test, run `terraform destroy` to clean up any resources that were created
Expand All @@ -161,11 +155,13 @@ func TestExamplesCompleteDisabledModule(t *testing.T) {
publicNATGateWayIds := terraform.OutputMap(t, terraformOptions, "public_az_ngw_ids")
publicRouteTableIds := terraform.OutputMap(t, terraformOptions, "public_az_route_table_ids")
publicSubnetIds := terraform.OutputMap(t, terraformOptions, "public_az_subnet_ids")
publicSubnetIpv6CidrBlocks := terraform.OutputMap(t, terraformOptions, "public_az_subnet_ipv6_cidr_blocks")

assert.Empty(t, privateNATGateWayIds)
assert.Empty(t, privateSubnetIds)
assert.Empty(t, privateRouteTableIds)
assert.Empty(t, publicNATGateWayIds)
assert.Empty(t, publicSubnetIds)
assert.Empty(t, publicRouteTableIds)
assert.Empty(t, publicSubnetIpv6CidrBlocks)
}
11 changes: 11 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,14 @@ variable "nat_gateway_enabled" {
default = "true"
}

variable "ipv6_enabled" {
description = "Flag to enable/disable IPv6 creation in public subnets"
type = bool
default = false
}

variable "ipv6_cidr_block" {
type = string
description = "Base IPv6 CIDR block which is divided into /64 subnet CIDR blocks"
default = null
}

0 comments on commit 9c5ef29

Please sign in to comment.