diff --git a/README.md b/README.md
index 39a3ed1..bc70071 100644
--- a/README.md
+++ b/README.md
@@ -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 |
@@ -317,6 +318,8 @@ Available targets:
| [environment](#input\_environment) | ID element. Usually used for region e.g. 'uw2', 'us-west-2', OR role 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no |
| [id\_length\_limit](#input\_id\_length\_limit) | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for keep the existing setting, which defaults to `0`.
Does not affect `id_full`. | `number` | `null` | no |
| [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 |
+| [ipv6\_cidr\_block](#input\_ipv6\_cidr\_block) | Base IPv6 CIDR block which is divided into /64 subnet CIDR blocks | `string` | `null` | no |
+| [ipv6\_enabled](#input\_ipv6\_enabled) | Flag to enable/disable IPv6 creation in public subnets | `bool` | `false` | no |
| [label\_key\_case](#input\_label\_key\_case) | Controls the letter case of the `tags` keys (label names) for tags generated by this module.
Does not affect keys of tags passed in via the `tags` input.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no |
| [label\_order](#input\_label\_order) | The order in which the labels (ID elements) appear in the `id`.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 6 labels ("tenant" is the 6th), but at least one must be present. | `list(string)` | `null` | no |
| [label\_value\_case](#input\_label\_value\_case) | Controls the letter case of ID elements (labels) as included in `id`,
set as tag values, and output by this module individually.
Does not affect values of tags passed in via the `tags` input.
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Set this to `title` and set `delimiter` to `""` to yield Pascal Case IDs.
Default value: `lower`. | `string` | `null` | no |
@@ -347,6 +350,7 @@ Available targets:
| [az\_subnet\_arns](#output\_az\_subnet\_arns) | Map of AZ names to subnet ARNs |
| [az\_subnet\_cidr\_blocks](#output\_az\_subnet\_cidr\_blocks) | Map of AZ names to subnet CIDR blocks |
| [az\_subnet\_ids](#output\_az\_subnet\_ids) | Map of AZ names to subnet IDs |
+| [az\_subnet\_ipv6\_cidr\_blocks](#output\_az\_subnet\_ipv6\_cidr\_blocks) | Map of AZ names to subnet IPv6 CIDR blocks |
| [az\_subnet\_map](#output\_az\_subnet\_map) | Map of AZ names to map of information about subnets |
diff --git a/docs/terraform.md b/docs/terraform.md
index d016ded..e7a9c7b 100644
--- a/docs/terraform.md
+++ b/docs/terraform.md
@@ -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 |
@@ -55,6 +56,8 @@
| [environment](#input\_environment) | ID element. Usually used for region e.g. 'uw2', 'us-west-2', OR role 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no |
| [id\_length\_limit](#input\_id\_length\_limit) | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for keep the existing setting, which defaults to `0`.
Does not affect `id_full`. | `number` | `null` | no |
| [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 |
+| [ipv6\_cidr\_block](#input\_ipv6\_cidr\_block) | Base IPv6 CIDR block which is divided into /64 subnet CIDR blocks | `string` | `null` | no |
+| [ipv6\_enabled](#input\_ipv6\_enabled) | Flag to enable/disable IPv6 creation in public subnets | `bool` | `false` | no |
| [label\_key\_case](#input\_label\_key\_case) | Controls the letter case of the `tags` keys (label names) for tags generated by this module.
Does not affect keys of tags passed in via the `tags` input.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no |
| [label\_order](#input\_label\_order) | The order in which the labels (ID elements) appear in the `id`.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 6 labels ("tenant" is the 6th), but at least one must be present. | `list(string)` | `null` | no |
| [label\_value\_case](#input\_label\_value\_case) | Controls the letter case of ID elements (labels) as included in `id`,
set as tag values, and output by this module individually.
Does not affect values of tags passed in via the `tags` input.
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Set this to `title` and set `delimiter` to `""` to yield Pascal Case IDs.
Default value: `lower`. | `string` | `null` | no |
@@ -85,5 +88,6 @@
| [az\_subnet\_arns](#output\_az\_subnet\_arns) | Map of AZ names to subnet ARNs |
| [az\_subnet\_cidr\_blocks](#output\_az\_subnet\_cidr\_blocks) | Map of AZ names to subnet CIDR blocks |
| [az\_subnet\_ids](#output\_az\_subnet\_ids) | Map of AZ names to subnet IDs |
+| [az\_subnet\_ipv6\_cidr\_blocks](#output\_az\_subnet\_ipv6\_cidr\_blocks) | Map of AZ names to subnet IPv6 CIDR blocks |
| [az\_subnet\_map](#output\_az\_subnet\_map) | Map of AZ names to map of information about subnets |
diff --git a/examples/complete/fixtures.us-east-2.tfvars b/examples/complete/fixtures.us-east-2.tfvars
index c5823f0..5f56e58 100644
--- a/examples/complete/fixtures.us-east-2.tfvars
+++ b/examples/complete/fixtures.us-east-2.tfvars
@@ -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"
\ No newline at end of file
+cidr_block = "172.16.0.0/16"
+
+ipv6_enabled = true
diff --git a/examples/complete/main.tf b/examples/complete/main.tf
index 26205be..1f3724b 100644
--- a/examples/complete/main.tf
+++ b/examples/complete/main.tf
@@ -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" {
@@ -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
}
@@ -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
}
@@ -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
@@ -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
}
-
diff --git a/examples/complete/outputs.tf b/examples/complete/outputs.tf
index f76982f..2a97c53 100644
--- a/examples/complete/outputs.tf
+++ b/examples/complete/outputs.tf
@@ -40,4 +40,8 @@ output "private_az_subnet_cidr_blocks" {
output "public_az_subnet_cidr_blocks" {
value = module.public_subnets.az_subnet_cidr_blocks
-}
\ No newline at end of file
+}
+
+output "public_az_subnet_ipv6_cidr_blocks" {
+ value = module.public_subnets.az_subnet_ipv6_cidr_blocks
+}
diff --git a/examples/complete/variables.tf b/examples/complete/variables.tf
index b0e215f..8e81974 100644
--- a/examples/complete/variables.tf
+++ b/examples/complete/variables.tf
@@ -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
+}
diff --git a/main.tf b/main.tf
index d9fd82d..2e3d6ac 100644
--- a/main.tf
+++ b/main.tf
@@ -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
}
}
}
diff --git a/outputs.tf b/outputs.tf
index 95ac2c1..f54f0de 100644
--- a/outputs.tf
+++ b/outputs.tf
@@ -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"
diff --git a/public.tf b/public.tf
index bff16da..b16a21f 100644
--- a/public.tf
+++ b/public.tf
@@ -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" {
@@ -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,
@@ -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
diff --git a/test/src/examples_complete_test.go b/test/src/examples_complete_test.go
index 585d1bc..f820403 100644
--- a/test/src/examples_complete_test.go
+++ b/test/src/examples_complete_test.go
@@ -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"}
@@ -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
@@ -161,6 +155,7 @@ 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)
@@ -168,4 +163,5 @@ func TestExamplesCompleteDisabledModule(t *testing.T) {
assert.Empty(t, publicNATGateWayIds)
assert.Empty(t, publicSubnetIds)
assert.Empty(t, publicRouteTableIds)
+ assert.Empty(t, publicSubnetIpv6CidrBlocks)
}
diff --git a/variables.tf b/variables.tf
index 261bd2e..9883486 100644
--- a/variables.tf
+++ b/variables.tf
@@ -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
+}