From be962ae74e48d797fa2d6859db5ceb0c922510db Mon Sep 17 00:00:00 2001 From: Anton Babenko Date: Mon, 2 Sep 2019 15:04:57 +0200 Subject: [PATCH] Add IPv6 support (#317) * IPv6 support Add variable "enable_ipv6" to allow enabling IPv6 support (resulting in passing "assign_generated_ipv6_cidr_block" to aws_vpc. Enabling IPv6 support further results in an Egress-only internet gateway being provisioned and routing tables of subnets being adjusted. Additional variables allow to choose the indices out of the /64 subnets based on the assigned /56 range. * Add example for IPv6 usage * Remove redundant parameter assign_generated_ipv6_cidr_block This is needed exactly when var.enable_ipv6 is true. * Set subnet ipv6_cidr_block to null if unused * Be picky about spelling * Revert unrelated change * More IPv6 spelling * Added IPv6 support to VPC module * Added IPv6 support to VPC module --- README.md | 28 +++++++- examples/ipv6/README.md | 26 ++++++++ examples/ipv6/main.tf | 37 +++++++++++ examples/ipv6/outputs.tf | 15 +++++ examples/network-acls/main.tf | 2 +- examples/secondary-cidr-blocks/main.tf | 7 +- examples/simple-vpc/main.tf | 2 +- main.tf | 92 ++++++++++++++++++++------ outputs.tf | 85 +++++++++++++++++------- variables.tf | 84 ++++++++++++++++++++++- 10 files changed, 324 insertions(+), 54 deletions(-) create mode 100644 examples/ipv6/README.md create mode 100644 examples/ipv6/main.tf create mode 100644 examples/ipv6/outputs.tf diff --git a/README.md b/README.md index 77f3f8054..5cb119c41 100644 --- a/README.md +++ b/README.md @@ -193,9 +193,11 @@ Sometimes it is handy to have public access to Redshift clusters (for example if ## Examples * [Simple VPC](https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master/examples/simple-vpc) +* [Simple VPC with secondary CIDR blocks](https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master/examples/secondary-cidr-blocks) * [Complete VPC](https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master/examples/complete-vpc) -* [Manage Default VPC](https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master/examples/manage-default-vpc) +* [VPC with IPv6 enabled](https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master/examples/ipv6) * [Network ACL](https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master/examples/network-acls) +* [Manage Default VPC](https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master/examples/manage-default-vpc) * Few tests and edge cases examples: [#46](https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master/examples/issue-46-no-private-subnets), [#44](https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master/examples/issue-44-asymmetric-private-subnets), [#108](https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master/examples/issue-108-route-already-exists) @@ -207,7 +209,7 @@ Sometimes it is handy to have public access to Redshift clusters (for example if | apigw\_endpoint\_private\_dns\_enabled | Whether or not to associate a private hosted zone with the specified VPC for API GW endpoint | bool | `"false"` | no | | apigw\_endpoint\_security\_group\_ids | The ID of one or more security groups to associate with the network interface for API GW endpoint | list(string) | `[]` | no | | apigw\_endpoint\_subnet\_ids | The ID of one or more subnets in which to create a network interface for API GW endpoint. Only a single subnet within an AZ is supported. If omitted, private subnets will be used. | list(string) | `[]` | no | -| assign\_generated\_ipv6\_cidr\_block | Requests an Amazon-provided IPv6 CIDR block with a /56 prefix length for the VPC. You cannot specify the range of IP addresses, or the size of the CIDR block | bool | `"false"` | no | +| assign\_ipv6\_address\_on\_creation | Assign IPv6 address on subnet, must be disabled to change IPv6 CIDRs. This is the IPv6 equivalent of map_public_ip_on_launch | bool | `"false"` | no | | azs | A list of availability zones in the region | list(string) | `[]` | no | | cidr | The CIDR block for the VPC. Default value is a valid CIDR, but not acceptable by AWS and should be overridden | string | `"0.0.0.0/0"` | no | | cloudtrail\_endpoint\_private\_dns\_enabled | Whether or not to associate a private hosted zone with the specified VPC for CloudTrail endpoint | bool | `"false"` | no | @@ -236,7 +238,9 @@ Sometimes it is handy to have public access to Redshift clusters (for example if | database\_inbound\_acl\_rules | Database subnets inbound network ACL rules | list(map(string)) | `[ { "cidr_block": "0.0.0.0/0", "from_port": 0, "protocol": "-1", "rule_action": "allow", "rule_number": 100, "to_port": 0 } ]` | no | | database\_outbound\_acl\_rules | Database subnets outbound network ACL rules | list(map(string)) | `[ { "cidr_block": "0.0.0.0/0", "from_port": 0, "protocol": "-1", "rule_action": "allow", "rule_number": 100, "to_port": 0 } ]` | no | | database\_route\_table\_tags | Additional tags for the database route tables | map(string) | `{}` | no | +| database\_subnet\_assign\_ipv6\_address\_on\_creation | Assign IPv6 address on database subnet, must be disabled to change IPv6 CIDRs. This is the IPv6 equivalent of map_public_ip_on_launch | bool | `"null"` | no | | database\_subnet\_group\_tags | Additional tags for the database subnet group | map(string) | `{}` | no | +| database\_subnet\_ipv6\_prefixes | Assigns IPv6 database subnet id based on the Amazon provided /56 prefix base 10 integer (0-256). Must be of equal length to the corresponding IPv4 subnet list | list | `[]` | no | | database\_subnet\_suffix | Suffix to append to database subnets name | string | `"db"` | no | | database\_subnet\_tags | Additional tags for the database subnets | map(string) | `{}` | no | | database\_subnets | A list of database subnets | list(string) | `[]` | no | @@ -281,6 +285,8 @@ Sometimes it is handy to have public access to Redshift clusters (for example if | elasticache\_inbound\_acl\_rules | Elasticache subnets inbound network ACL rules | list(map(string)) | `[ { "cidr_block": "0.0.0.0/0", "from_port": 0, "protocol": "-1", "rule_action": "allow", "rule_number": 100, "to_port": 0 } ]` | no | | elasticache\_outbound\_acl\_rules | Elasticache subnets outbound network ACL rules | list(map(string)) | `[ { "cidr_block": "0.0.0.0/0", "from_port": 0, "protocol": "-1", "rule_action": "allow", "rule_number": 100, "to_port": 0 } ]` | no | | elasticache\_route\_table\_tags | Additional tags for the elasticache route tables | map(string) | `{}` | no | +| elasticache\_subnet\_assign\_ipv6\_address\_on\_creation | Assign IPv6 address on elasticache subnet, must be disabled to change IPv6 CIDRs. This is the IPv6 equivalent of map_public_ip_on_launch | bool | `"null"` | no | +| elasticache\_subnet\_ipv6\_prefixes | Assigns IPv6 elasticache subnet id based on the Amazon provided /56 prefix base 10 integer (0-256). Must be of equal length to the corresponding IPv4 subnet list | list | `[]` | no | | elasticache\_subnet\_suffix | Suffix to append to elasticache subnets name | string | `"elasticache"` | no | | elasticache\_subnet\_tags | Additional tags for the elasticache subnets | map(string) | `{}` | no | | elasticache\_subnets | A list of elasticache subnets | list(string) | `[]` | no | @@ -306,6 +312,7 @@ Sometimes it is handy to have public access to Redshift clusters (for example if | enable\_elasticloadbalancing\_endpoint | Should be true if you want to provision a Elastic Load Balancing endpoint to the VPC | bool | `"false"` | no | | enable\_events\_endpoint | Should be true if you want to provision a CloudWatch Events endpoint to the VPC | bool | `"false"` | no | | enable\_git\_codecommit\_endpoint | Should be true if you want to provision an Git Codecommit endpoint to the VPC | string | `"false"` | no | +| enable\_ipv6 | Requests an Amazon-provided IPv6 CIDR block with a /56 prefix length for the VPC. You cannot specify the range of IP addresses, or the size of the CIDR block. | bool | `"false"` | no | | enable\_kinesis\_firehose\_endpoint | Should be true if you want to provision a Kinesis Firehose endpoint to the VPC | bool | `"false"` | no | | enable\_kinesis\_streams\_endpoint | Should be true if you want to provision a Kinesis Streams endpoint to the VPC | bool | `"false"` | no | | enable\_kms\_endpoint | Should be true if you want to provision a KMS endpoint to the VPC | bool | `"false"` | no | @@ -335,6 +342,8 @@ Sometimes it is handy to have public access to Redshift clusters (for example if | intra\_inbound\_acl\_rules | Intra subnets inbound network ACLs | list(map(string)) | `[ { "cidr_block": "0.0.0.0/0", "from_port": 0, "protocol": "-1", "rule_action": "allow", "rule_number": 100, "to_port": 0 } ]` | no | | intra\_outbound\_acl\_rules | Intra subnets outbound network ACLs | list(map(string)) | `[ { "cidr_block": "0.0.0.0/0", "from_port": 0, "protocol": "-1", "rule_action": "allow", "rule_number": 100, "to_port": 0 } ]` | no | | intra\_route\_table\_tags | Additional tags for the intra route tables | map(string) | `{}` | no | +| intra\_subnet\_assign\_ipv6\_address\_on\_creation | Assign IPv6 address on intra subnet, must be disabled to change IPv6 CIDRs. This is the IPv6 equivalent of map_public_ip_on_launch | bool | `"null"` | no | +| intra\_subnet\_ipv6\_prefixes | Assigns IPv6 intra subnet id based on the Amazon provided /56 prefix base 10 integer (0-256). Must be of equal length to the corresponding IPv4 subnet list | list | `[]` | no | | intra\_subnet\_suffix | Suffix to append to intra subnets name | string | `"intra"` | no | | intra\_subnet\_tags | Additional tags for the intra subnets | map(string) | `{}` | no | | intra\_subnets | A list of intra subnets | list(string) | `[]` | no | @@ -365,6 +374,8 @@ Sometimes it is handy to have public access to Redshift clusters (for example if | private\_inbound\_acl\_rules | Private subnets inbound network ACLs | list(map(string)) | `[ { "cidr_block": "0.0.0.0/0", "from_port": 0, "protocol": "-1", "rule_action": "allow", "rule_number": 100, "to_port": 0 } ]` | no | | private\_outbound\_acl\_rules | Private subnets outbound network ACLs | list(map(string)) | `[ { "cidr_block": "0.0.0.0/0", "from_port": 0, "protocol": "-1", "rule_action": "allow", "rule_number": 100, "to_port": 0 } ]` | no | | private\_route\_table\_tags | Additional tags for the private route tables | map(string) | `{}` | no | +| private\_subnet\_assign\_ipv6\_address\_on\_creation | Assign IPv6 address on private subnet, must be disabled to change IPv6 CIDRs. This is the IPv6 equivalent of map_public_ip_on_launch | bool | `"null"` | no | +| private\_subnet\_ipv6\_prefixes | Assigns IPv6 private subnet id based on the Amazon provided /56 prefix base 10 integer (0-256). Must be of equal length to the corresponding IPv4 subnet list | list | `[]` | no | | private\_subnet\_suffix | Suffix to append to private subnets name | string | `"private"` | no | | private\_subnet\_tags | Additional tags for the private subnets | map(string) | `{}` | no | | private\_subnets | A list of private subnets inside the VPC | list(string) | `[]` | no | @@ -375,6 +386,8 @@ Sometimes it is handy to have public access to Redshift clusters (for example if | public\_inbound\_acl\_rules | Public subnets inbound network ACLs | list(map(string)) | `[ { "cidr_block": "0.0.0.0/0", "from_port": 0, "protocol": "-1", "rule_action": "allow", "rule_number": 100, "to_port": 0 } ]` | no | | public\_outbound\_acl\_rules | Public subnets outbound network ACLs | list(map(string)) | `[ { "cidr_block": "0.0.0.0/0", "from_port": 0, "protocol": "-1", "rule_action": "allow", "rule_number": 100, "to_port": 0 } ]` | no | | public\_route\_table\_tags | Additional tags for the public route tables | map(string) | `{}` | no | +| public\_subnet\_assign\_ipv6\_address\_on\_creation | Assign IPv6 address on public subnet, must be disabled to change IPv6 CIDRs. This is the IPv6 equivalent of map_public_ip_on_launch | bool | `"null"` | no | +| public\_subnet\_ipv6\_prefixes | Assigns IPv6 public subnet id based on the Amazon provided /56 prefix base 10 integer (0-256). Must be of equal length to the corresponding IPv4 subnet list | list | `[]` | no | | public\_subnet\_suffix | Suffix to append to public subnets name | string | `"public"` | no | | public\_subnet\_tags | Additional tags for the public subnets | map(string) | `{}` | no | | public\_subnets | A list of public subnets inside the VPC | list(string) | `[]` | no | @@ -383,7 +396,9 @@ Sometimes it is handy to have public access to Redshift clusters (for example if | redshift\_inbound\_acl\_rules | Redshift subnets inbound network ACL rules | list(map(string)) | `[ { "cidr_block": "0.0.0.0/0", "from_port": 0, "protocol": "-1", "rule_action": "allow", "rule_number": 100, "to_port": 0 } ]` | no | | redshift\_outbound\_acl\_rules | Redshift subnets outbound network ACL rules | list(map(string)) | `[ { "cidr_block": "0.0.0.0/0", "from_port": 0, "protocol": "-1", "rule_action": "allow", "rule_number": 100, "to_port": 0 } ]` | no | | redshift\_route\_table\_tags | Additional tags for the redshift route tables | map(string) | `{}` | no | +| redshift\_subnet\_assign\_ipv6\_address\_on\_creation | Assign IPv6 address on redshift subnet, must be disabled to change IPv6 CIDRs. This is the IPv6 equivalent of map_public_ip_on_launch | bool | `"null"` | no | | redshift\_subnet\_group\_tags | Additional tags for the redshift subnet group | map(string) | `{}` | no | +| redshift\_subnet\_ipv6\_prefixes | Assigns IPv6 redshift subnet id based on the Amazon provided /56 prefix base 10 integer (0-256). Must be of equal length to the corresponding IPv4 subnet list | list | `[]` | no | | redshift\_subnet\_suffix | Suffix to append to redshift subnets name | string | `"redshift"` | no | | redshift\_subnet\_tags | Additional tags for the redshift subnets | map(string) | `{}` | no | | redshift\_subnets | A list of redshift subnets | list(string) | `[]` | no | @@ -424,6 +439,7 @@ Sometimes it is handy to have public access to Redshift clusters (for example if | database\_subnet\_group | ID of database subnet group | | database\_subnets | List of IDs of database subnets | | database\_subnets\_cidr\_blocks | List of cidr_blocks of database subnets | +| database\_subnets\_ipv6\_cidr\_blocks | List of IPv6 cidr_blocks of database subnets in an IPv6 enabled VPC | | default\_network\_acl\_id | The ID of the default network ACL | | default\_route\_table\_id | The ID of the default route table | | default\_security\_group\_id | The ID of the security group created by default on VPC creation | @@ -436,6 +452,7 @@ Sometimes it is handy to have public access to Redshift clusters (for example if | default\_vpc\_id | The ID of the VPC | | default\_vpc\_instance\_tenancy | Tenancy of instances spin up within VPC | | default\_vpc\_main\_route\_table\_id | The ID of the main route table associated with this VPC | +| egress\_only\_internet\_gateway\_id | The ID of the egress only Internet Gateway | | elasticache\_network\_acl\_id | ID of the elasticache network ACL | | elasticache\_route\_table\_ids | List of IDs of elasticache route tables | | elasticache\_subnet\_arns | List of ARNs of elasticache subnets | @@ -443,12 +460,14 @@ Sometimes it is handy to have public access to Redshift clusters (for example if | elasticache\_subnet\_group\_name | Name of elasticache subnet group | | elasticache\_subnets | List of IDs of elasticache subnets | | elasticache\_subnets\_cidr\_blocks | List of cidr_blocks of elasticache subnets | +| elasticache\_subnets\_ipv6\_cidr\_blocks | List of IPv6 cidr_blocks of elasticache subnets in an IPv6 enabled VPC | | igw\_id | The ID of the Internet Gateway | | intra\_network\_acl\_id | ID of the intra network ACL | | intra\_route\_table\_ids | List of IDs of intra route tables | | intra\_subnet\_arns | List of ARNs of intra subnets | | intra\_subnets | List of IDs of intra subnets | | intra\_subnets\_cidr\_blocks | List of cidr_blocks of intra subnets | +| intra\_subnets\_ipv6\_cidr\_blocks | List of IPv6 cidr_blocks of intra subnets in an IPv6 enabled VPC | | name | The name of the VPC specified as argument to this module | | 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 | @@ -458,17 +477,20 @@ Sometimes it is handy to have public access to Redshift clusters (for example if | private\_subnet\_arns | List of ARNs of private subnets | | private\_subnets | List of IDs of private subnets | | private\_subnets\_cidr\_blocks | List of cidr_blocks of private subnets | +| private\_subnets\_ipv6\_cidr\_blocks | List of IPv6 cidr_blocks of private subnets in an IPv6 enabled VPC | | public\_network\_acl\_id | ID of the public network ACL | | public\_route\_table\_ids | List of IDs of public route tables | | public\_subnet\_arns | List of ARNs of public subnets | | public\_subnets | List of IDs of public subnets | | public\_subnets\_cidr\_blocks | List of cidr_blocks of public subnets | +| public\_subnets\_ipv6\_cidr\_blocks | List of IPv6 cidr_blocks of public subnets in an IPv6 enabled VPC | | redshift\_network\_acl\_id | ID of the redshift network ACL | | redshift\_route\_table\_ids | List of IDs of redshift route tables | | redshift\_subnet\_arns | List of ARNs of redshift subnets | | redshift\_subnet\_group | ID of redshift subnet group | | redshift\_subnets | List of IDs of redshift subnets | | redshift\_subnets\_cidr\_blocks | List of cidr_blocks of redshift subnets | +| redshift\_subnets\_ipv6\_cidr\_blocks | List of IPv6 cidr_blocks of redshift subnets in an IPv6 enabled VPC | | vgw\_id | The ID of the VPN Gateway | | vpc\_arn | The ARN of the VPC | | vpc\_cidr\_block | The CIDR block of the VPC | @@ -534,6 +556,8 @@ Sometimes it is handy to have public access to Redshift clusters (for example if | vpc\_endpoint\_ssmmessages\_network\_interface\_ids | One or more network interfaces for the VPC Endpoint for SSMMESSAGES. | | vpc\_id | The ID of the VPC | | vpc\_instance\_tenancy | Tenancy of instances spin up within VPC | +| vpc\_ipv6\_association\_id | The association ID for the IPv6 CIDR block | +| vpc\_ipv6\_cidr\_block | The IPv6 CIDR block | | vpc\_main\_route\_table\_id | The ID of the main route table associated with this VPC | | vpc\_secondary\_cidr\_blocks | List of secondary CIDR blocks of the VPC | diff --git a/examples/ipv6/README.md b/examples/ipv6/README.md new file mode 100644 index 000000000..5399a87dd --- /dev/null +++ b/examples/ipv6/README.md @@ -0,0 +1,26 @@ +# VPC with IPv6 enabled + +Configuration in this directory creates set of VPC resources with IPv6 enabled on VPC and subnets. + +## Usage + +To run this example you need to execute: + +```bash +$ terraform init +$ terraform plan +$ terraform apply +``` + +Note that this example may create resources which can cost money (AWS Elastic IP, for example). Run `terraform destroy` when you don't need these resources. + + +## Outputs + +| Name | Description | +|------|-------------| +| ipv6\_association\_id | The IPv6 CIDR block | +| ipv6\_cidr\_block | The association ID for the IPv6 CIDR block | +| vpc\_id | The ID of the VPC | + + diff --git a/examples/ipv6/main.tf b/examples/ipv6/main.tf new file mode 100644 index 000000000..8bb2782d4 --- /dev/null +++ b/examples/ipv6/main.tf @@ -0,0 +1,37 @@ +provider "aws" { + region = "eu-west-1" +} + +data "aws_availability_zones" "available" {} + +module "vpc" { + source = "../.." + + name = "ipv6" + + cidr = "10.0.0.0/16" + + azs = [data.aws_availability_zones.available.names[0], data.aws_availability_zones.available.names[1]] + private_subnets = ["10.0.1.0/24", "10.0.2.0/24"] + public_subnets = ["10.0.101.0/24", "10.0.102.0/24"] + database_subnets = ["10.0.103.0/24", "10.0.104.0/24"] + + enable_nat_gateway = false + + create_database_subnet_route_table = true + create_database_internet_gateway_route = true + + enable_ipv6 = true + assign_ipv6_address_on_creation = true + + private_subnet_assign_ipv6_address_on_creation = false + + public_subnet_ipv6_prefixes = [0, 1] + private_subnet_ipv6_prefixes = [2, 3] + database_subnet_ipv6_prefixes = [4, 5] + + tags = { + Owner = "user" + Environment = "dev" + } +} diff --git a/examples/ipv6/outputs.tf b/examples/ipv6/outputs.tf new file mode 100644 index 000000000..9b76b3693 --- /dev/null +++ b/examples/ipv6/outputs.tf @@ -0,0 +1,15 @@ +# VPC +output "vpc_id" { + description = "The ID of the VPC" + value = module.vpc.vpc_id +} + +output "ipv6_association_id" { + description = "The IPv6 CIDR block" + value = module.vpc.vpc_ipv6_cidr_block +} + +output "ipv6_cidr_block" { + description = "The association ID for the IPv6 CIDR block" + value = module.vpc.vpc_ipv6_association_id +} diff --git a/examples/network-acls/main.tf b/examples/network-acls/main.tf index c1a1dab90..b7bee06f4 100644 --- a/examples/network-acls/main.tf +++ b/examples/network-acls/main.tf @@ -26,7 +26,7 @@ module "vpc" { private_dedicated_network_acl = true - assign_generated_ipv6_cidr_block = true + enable_ipv6 = true enable_nat_gateway = false single_nat_gateway = true diff --git a/examples/secondary-cidr-blocks/main.tf b/examples/secondary-cidr-blocks/main.tf index a49b973de..6c621913e 100644 --- a/examples/secondary-cidr-blocks/main.tf +++ b/examples/secondary-cidr-blocks/main.tf @@ -14,9 +14,10 @@ module "vpc" { private_subnets = ["10.0.1.0/24", "10.1.2.0/24", "10.2.3.0/24"] public_subnets = ["10.0.101.0/24", "10.1.102.0/24", "10.2.103.0/24"] - assign_generated_ipv6_cidr_block = true - enable_nat_gateway = true - single_nat_gateway = true + enable_ipv6 = true + + enable_nat_gateway = true + single_nat_gateway = true public_subnet_tags = { Name = "overridden-name-public" diff --git a/examples/simple-vpc/main.tf b/examples/simple-vpc/main.tf index c0b094835..d96df4696 100644 --- a/examples/simple-vpc/main.tf +++ b/examples/simple-vpc/main.tf @@ -18,7 +18,7 @@ module "vpc" { 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"] - assign_generated_ipv6_cidr_block = true + enable_ipv6 = true enable_nat_gateway = true single_nat_gateway = true diff --git a/main.tf b/main.tf index e6146968e..52e1b0f68 100644 --- a/main.tf +++ b/main.tf @@ -28,7 +28,7 @@ resource "aws_vpc" "this" { instance_tenancy = var.instance_tenancy enable_dns_hostnames = var.enable_dns_hostnames enable_dns_support = var.enable_dns_support - assign_generated_ipv6_cidr_block = var.assign_generated_ipv6_cidr_block + assign_generated_ipv6_cidr_block = var.enable_ipv6 tags = merge( { @@ -95,6 +95,12 @@ resource "aws_internet_gateway" "this" { ) } +resource "aws_egress_only_internet_gateway" "this" { + count = var.create_vpc && var.enable_ipv6 && local.max_subnet_length > 0 ? 1 : 0 + + vpc_id = local.vpc_id +} + ################ # Publiс routes ################ @@ -124,6 +130,14 @@ resource "aws_route" "public_internet_gateway" { } } +resource "aws_route" "public_internet_gateway_ipv6" { + count = var.create_vpc && var.enable_ipv6 && length(var.public_subnets) > 0 ? 1 : 0 + + route_table_id = aws_route_table.public[0].id + destination_ipv6_cidr_block = "::/0" + gateway_id = aws_internet_gateway.this[0].id +} + ################# # Private routes # There are as many routing tables as the number of NAT gateways @@ -193,6 +207,18 @@ resource "aws_route" "database_nat_gateway" { } } +resource "aws_route" "database_ipv6_egress" { + count = var.create_vpc && var.enable_ipv6 && var.create_database_subnet_route_table && length(var.database_subnets) > 0 && var.create_database_internet_gateway_route ? 1 : 0 + + route_table_id = aws_route_table.database[0].id + destination_ipv6_cidr_block = "::/0" + egress_only_gateway_id = aws_egress_only_internet_gateway.this[0].id + + timeouts { + create = "5m" + } +} + ################# # Redshift routes ################# @@ -250,10 +276,13 @@ resource "aws_route_table" "intra" { resource "aws_subnet" "public" { count = var.create_vpc && length(var.public_subnets) > 0 && (false == var.one_nat_gateway_per_az || length(var.public_subnets) >= length(var.azs)) ? length(var.public_subnets) : 0 - vpc_id = local.vpc_id - cidr_block = element(concat(var.public_subnets, [""]), count.index) - availability_zone = element(var.azs, count.index) - map_public_ip_on_launch = var.map_public_ip_on_launch + vpc_id = local.vpc_id + cidr_block = element(concat(var.public_subnets, [""]), count.index) + availability_zone = element(var.azs, count.index) + map_public_ip_on_launch = var.map_public_ip_on_launch + assign_ipv6_address_on_creation = var.public_subnet_assign_ipv6_address_on_creation == null ? var.assign_ipv6_address_on_creation : var.public_subnet_assign_ipv6_address_on_creation + + ipv6_cidr_block = var.enable_ipv6 && length(var.public_subnet_ipv6_prefixes) > 0 ? cidrsubnet(aws_vpc.this[0].ipv6_cidr_block, 8, var.public_subnet_ipv6_prefixes[count.index]) : null tags = merge( { @@ -274,9 +303,12 @@ resource "aws_subnet" "public" { resource "aws_subnet" "private" { count = var.create_vpc && length(var.private_subnets) > 0 ? length(var.private_subnets) : 0 - vpc_id = local.vpc_id - cidr_block = var.private_subnets[count.index] - availability_zone = element(var.azs, count.index) + vpc_id = local.vpc_id + cidr_block = var.private_subnets[count.index] + availability_zone = element(var.azs, count.index) + assign_ipv6_address_on_creation = var.private_subnet_assign_ipv6_address_on_creation == null ? var.assign_ipv6_address_on_creation : var.private_subnet_assign_ipv6_address_on_creation + + ipv6_cidr_block = var.enable_ipv6 && length(var.private_subnet_ipv6_prefixes) > 0 ? cidrsubnet(aws_vpc.this[0].ipv6_cidr_block, 8, var.private_subnet_ipv6_prefixes[count.index]) : null tags = merge( { @@ -297,9 +329,12 @@ resource "aws_subnet" "private" { resource "aws_subnet" "database" { count = var.create_vpc && length(var.database_subnets) > 0 ? length(var.database_subnets) : 0 - vpc_id = local.vpc_id - cidr_block = var.database_subnets[count.index] - availability_zone = element(var.azs, count.index) + vpc_id = local.vpc_id + cidr_block = var.database_subnets[count.index] + availability_zone = element(var.azs, count.index) + assign_ipv6_address_on_creation = var.database_subnet_assign_ipv6_address_on_creation == null ? var.assign_ipv6_address_on_creation : var.database_subnet_assign_ipv6_address_on_creation + + ipv6_cidr_block = var.enable_ipv6 && length(var.database_subnet_ipv6_prefixes) > 0 ? cidrsubnet(aws_vpc.this[0].ipv6_cidr_block, 8, var.database_subnet_ipv6_prefixes[count.index]) : null tags = merge( { @@ -336,9 +371,12 @@ resource "aws_db_subnet_group" "database" { resource "aws_subnet" "redshift" { count = var.create_vpc && length(var.redshift_subnets) > 0 ? length(var.redshift_subnets) : 0 - vpc_id = local.vpc_id - cidr_block = var.redshift_subnets[count.index] - availability_zone = element(var.azs, count.index) + vpc_id = local.vpc_id + cidr_block = var.redshift_subnets[count.index] + availability_zone = element(var.azs, count.index) + assign_ipv6_address_on_creation = var.redshift_subnet_assign_ipv6_address_on_creation == null ? var.assign_ipv6_address_on_creation : var.redshift_subnet_assign_ipv6_address_on_creation + + ipv6_cidr_block = var.enable_ipv6 && length(var.redshift_subnet_ipv6_prefixes) > 0 ? cidrsubnet(aws_vpc.this[0].ipv6_cidr_block, 8, var.redshift_subnet_ipv6_prefixes[count.index]) : null tags = merge( { @@ -375,9 +413,12 @@ resource "aws_redshift_subnet_group" "redshift" { resource "aws_subnet" "elasticache" { count = var.create_vpc && length(var.elasticache_subnets) > 0 ? length(var.elasticache_subnets) : 0 - vpc_id = local.vpc_id - cidr_block = var.elasticache_subnets[count.index] - availability_zone = element(var.azs, count.index) + vpc_id = local.vpc_id + cidr_block = var.elasticache_subnets[count.index] + availability_zone = element(var.azs, count.index) + assign_ipv6_address_on_creation = var.elasticache_subnet_assign_ipv6_address_on_creation == null ? var.assign_ipv6_address_on_creation : var.elasticache_subnet_assign_ipv6_address_on_creation + + ipv6_cidr_block = var.enable_ipv6 && length(var.elasticache_subnet_ipv6_prefixes) > 0 ? cidrsubnet(aws_vpc.this[0].ipv6_cidr_block, 8, var.elasticache_subnet_ipv6_prefixes[count.index]) : null tags = merge( { @@ -406,9 +447,12 @@ resource "aws_elasticache_subnet_group" "elasticache" { resource "aws_subnet" "intra" { count = var.create_vpc && length(var.intra_subnets) > 0 ? length(var.intra_subnets) : 0 - vpc_id = local.vpc_id - cidr_block = var.intra_subnets[count.index] - availability_zone = element(var.azs, count.index) + vpc_id = local.vpc_id + cidr_block = var.intra_subnets[count.index] + availability_zone = element(var.azs, count.index) + assign_ipv6_address_on_creation = var.intra_subnet_assign_ipv6_address_on_creation == null ? var.assign_ipv6_address_on_creation : var.intra_subnet_assign_ipv6_address_on_creation + + ipv6_cidr_block = var.enable_ipv6 && length(var.intra_subnet_ipv6_prefixes) > 0 ? cidrsubnet(aws_vpc.this[0].ipv6_cidr_block, 8, var.intra_subnet_ipv6_prefixes[count.index]) : null tags = merge( { @@ -824,6 +868,14 @@ resource "aws_route" "private_nat_gateway" { } } +resource "aws_route" "private_ipv6_egress" { + count = var.enable_ipv6 ? length(var.private_subnets) : 0 + + route_table_id = element(aws_route_table.private.*.id, count.index) + destination_ipv6_cidr_block = "::/0" + egress_only_gateway_id = element(aws_egress_only_internet_gateway.this.*.id, 0) +} + ###################### # VPC Endpoint for S3 ###################### diff --git a/outputs.tf b/outputs.tf index 1f43e8151..6950f8aee 100644 --- a/outputs.tf +++ b/outputs.tf @@ -45,7 +45,7 @@ output "vpc_enable_dns_hostnames" { //output "vpc_enable_classiclink" { // description = "Whether or not the VPC has Classiclink enabled" -// value = "${element(concat(aws_vpc.this.*.enable_classiclink, list("")), 0)}" +// value = concat(aws_vpc.this.*.enable_classiclink, [""])[0] //} output "vpc_main_route_table_id" { @@ -53,15 +53,15 @@ output "vpc_main_route_table_id" { value = concat(aws_vpc.this.*.main_route_table_id, [""])[0] } -//output "vpc_ipv6_association_id" { -// description = "The association ID for the IPv6 CIDR block" -// value = "${element(concat(aws_vpc.this.*.ipv6_association_id, list("")), 0)}" -//} -// -//output "vpc_ipv6_cidr_block" { -// description = "The IPv6 CIDR block" -// value = "${element(concat(aws_vpc.this.*.ipv6_cidr_block, list("")), 0)}" -//} +output "vpc_ipv6_association_id" { + description = "The association ID for the IPv6 CIDR block" + value = concat(aws_vpc.this.*.ipv6_association_id, [""])[0] +} + +output "vpc_ipv6_cidr_block" { + description = "The IPv6 CIDR block" + value = concat(aws_vpc.this.*.ipv6_cidr_block, [""])[0] +} output "vpc_secondary_cidr_blocks" { description = "List of secondary CIDR blocks of the VPC" @@ -83,6 +83,11 @@ output "private_subnets_cidr_blocks" { value = aws_subnet.private.*.cidr_block } +output "private_subnets_ipv6_cidr_blocks" { + description = "List of IPv6 cidr_blocks of private subnets in an IPv6 enabled VPC" + value = aws_subnet.private.*.ipv6_cidr_block +} + output "public_subnets" { description = "List of IDs of public subnets" value = aws_subnet.public.*.id @@ -98,6 +103,11 @@ output "public_subnets_cidr_blocks" { value = aws_subnet.public.*.cidr_block } +output "public_subnets_ipv6_cidr_blocks" { + description = "List of IPv6 cidr_blocks of public subnets in an IPv6 enabled VPC" + value = aws_subnet.public.*.ipv6_cidr_block +} + output "database_subnets" { description = "List of IDs of database subnets" value = aws_subnet.database.*.id @@ -113,6 +123,11 @@ output "database_subnets_cidr_blocks" { value = aws_subnet.database.*.cidr_block } +output "database_subnets_ipv6_cidr_blocks" { + description = "List of IPv6 cidr_blocks of database subnets in an IPv6 enabled VPC" + value = aws_subnet.database.*.ipv6_cidr_block +} + output "database_subnet_group" { description = "ID of database subnet group" value = concat(aws_db_subnet_group.database.*.id, [""])[0] @@ -133,6 +148,11 @@ output "redshift_subnets_cidr_blocks" { value = aws_subnet.redshift.*.cidr_block } +output "redshift_subnets_ipv6_cidr_blocks" { + description = "List of IPv6 cidr_blocks of redshift subnets in an IPv6 enabled VPC" + value = aws_subnet.redshift.*.ipv6_cidr_block +} + output "redshift_subnet_group" { description = "ID of redshift subnet group" value = concat(aws_redshift_subnet_group.redshift.*.id, [""])[0] @@ -153,6 +173,11 @@ output "elasticache_subnets_cidr_blocks" { value = aws_subnet.elasticache.*.cidr_block } +output "elasticache_subnets_ipv6_cidr_blocks" { + description = "List of IPv6 cidr_blocks of elasticache subnets in an IPv6 enabled VPC" + value = aws_subnet.elasticache.*.ipv6_cidr_block +} + output "intra_subnets" { description = "List of IDs of intra subnets" value = aws_subnet.intra.*.id @@ -168,6 +193,11 @@ output "intra_subnets_cidr_blocks" { value = aws_subnet.intra.*.cidr_block } +output "intra_subnets_ipv6_cidr_blocks" { + description = "List of IPv6 cidr_blocks of intra subnets in an IPv6 enabled VPC" + value = aws_subnet.intra.*.ipv6_cidr_block +} + output "elasticache_subnet_group" { description = "ID of elasticache subnet group" value = concat(aws_elasticache_subnet_group.elasticache.*.id, [""])[0] @@ -228,6 +258,11 @@ output "igw_id" { value = concat(aws_internet_gateway.this.*.id, [""])[0] } +output "egress_only_internet_gateway_id" { + description = "The ID of the egress only Internet Gateway" + value = concat(aws_egress_only_internet_gateway.this.*.id, [""])[0] +} + output "vgw_id" { description = "The ID of the VPN Gateway" value = concat( @@ -279,7 +314,7 @@ output "default_vpc_enable_dns_hostnames" { //output "default_vpc_enable_classiclink" { // description = "Whether or not the VPC has Classiclink enabled" -// value = "${element(concat(aws_default_vpc.this.*.enable_classiclink, list("")), 0)}" +// value = concat(aws_default_vpc.this.*.enable_classiclink, [""])[0] //} output "default_vpc_main_route_table_id" { @@ -289,12 +324,12 @@ output "default_vpc_main_route_table_id" { //output "default_vpc_ipv6_association_id" { // description = "The association ID for the IPv6 CIDR block" -// value = "${element(concat(aws_default_vpc.this.*.ipv6_association_id, list("")), 0)}" +// value = concat(aws_default_vpc.this.*.ipv6_association_id, [""])[0] //} // //output "default_vpc_ipv6_cidr_block" { // description = "The IPv6 CIDR block" -// value = "${element(concat(aws_default_vpc.this.*.ipv6_cidr_block, list("")), 0)}" +// value = concat(aws_default_vpc.this.*.ipv6_cidr_block, [""])[0] //} output "public_network_acl_id" { @@ -350,17 +385,17 @@ output "vpc_endpoint_dynamodb_pl_id" { output "vpc_endpoint_sqs_id" { description = "The ID of VPC endpoint for SQS" - value = "${element(concat(aws_vpc_endpoint.sqs.*.id, list("")), 0)}" + value = concat(aws_vpc_endpoint.sqs.*.id, [""])[0] } output "vpc_endpoint_sqs_network_interface_ids" { description = "One or more network interfaces for the VPC Endpoint for SQS." - value = "${flatten(aws_vpc_endpoint.sqs.*.network_interface_ids)}" + value = flatten(aws_vpc_endpoint.sqs.*.network_interface_ids) } output "vpc_endpoint_sqs_dns_entry" { description = "The DNS entries for the VPC Endpoint for SQS." - value = "${flatten(aws_vpc_endpoint.sqs.*.dns_entry)}" + value = flatten(aws_vpc_endpoint.sqs.*.dns_entry) } output "vpc_endpoint_ssm_id" { @@ -485,47 +520,47 @@ output "vpc_endpoint_apigw_dns_entry" { output "vpc_endpoint_ecs_id" { description = "The ID of VPC endpoint for ECS" - value = "${element(concat(aws_vpc_endpoint.ecs.*.id, list("")), 0)}" + value = concat(aws_vpc_endpoint.ecs.*.id, [""])[0] } output "vpc_endpoint_ecs_network_interface_ids" { description = "One or more network interfaces for the VPC Endpoint for ECS." - value = "${flatten(aws_vpc_endpoint.ecs.*.network_interface_ids)}" + value = flatten(aws_vpc_endpoint.ecs.*.network_interface_ids) } output "vpc_endpoint_ecs_dns_entry" { description = "The DNS entries for the VPC Endpoint for ECS." - value = "${flatten(aws_vpc_endpoint.ecs.*.dns_entry)}" + value = flatten(aws_vpc_endpoint.ecs.*.dns_entry) } output "vpc_endpoint_ecs_agent_id" { description = "The ID of VPC endpoint for ECS Agent" - value = "${element(concat(aws_vpc_endpoint.ecs_agent.*.id, list("")), 0)}" + value = concat(aws_vpc_endpoint.ecs_agent.*.id, [""])[0] } output "vpc_endpoint_ecs_agent_network_interface_ids" { description = "One or more network interfaces for the VPC Endpoint for ECS Agent." - value = "${flatten(aws_vpc_endpoint.ecs_agent.*.network_interface_ids)}" + value = flatten(aws_vpc_endpoint.ecs_agent.*.network_interface_ids) } output "vpc_endpoint_ecs_agent_dns_entry" { description = "The DNS entries for the VPC Endpoint for ECS Agent." - value = "${flatten(aws_vpc_endpoint.ecs_agent.*.dns_entry)}" + value = flatten(aws_vpc_endpoint.ecs_agent.*.dns_entry) } output "vpc_endpoint_ecs_telemetry_id" { description = "The ID of VPC endpoint for ECS Telemetry" - value = "${element(concat(aws_vpc_endpoint.ecs_telemetry.*.id, list("")), 0)}" + value = concat(aws_vpc_endpoint.ecs_telemetry.*.id, [""])[0] } output "vpc_endpoint_ecs_telemetry_network_interface_ids" { description = "One or more network interfaces for the VPC Endpoint for ECS Telemetry." - value = "${flatten(aws_vpc_endpoint.ecs_telemetry.*.network_interface_ids)}" + value = flatten(aws_vpc_endpoint.ecs_telemetry.*.network_interface_ids) } output "vpc_endpoint_ecs_telemetry_dns_entry" { description = "The DNS entries for the VPC Endpoint for ECS Telemetry." - value = "${flatten(aws_vpc_endpoint.ecs_telemetry.*.dns_entry)}" + value = flatten(aws_vpc_endpoint.ecs_telemetry.*.dns_entry) } output "vpc_endpoint_sns_id" { diff --git a/variables.tf b/variables.tf index e83983643..0723dab67 100644 --- a/variables.tf +++ b/variables.tf @@ -6,20 +6,100 @@ variable "create_vpc" { variable "name" { description = "Name to be used on all the resources as identifier" + type = string default = "" } variable "cidr" { description = "The CIDR block for the VPC. Default value is a valid CIDR, but not acceptable by AWS and should be overridden" + type = string default = "0.0.0.0/0" } -variable "assign_generated_ipv6_cidr_block" { - description = "Requests an Amazon-provided IPv6 CIDR block with a /56 prefix length for the VPC. You cannot specify the range of IP addresses, or the size of the CIDR block" +variable "enable_ipv6" { + description = "Requests an Amazon-provided IPv6 CIDR block with a /56 prefix length for the VPC. You cannot specify the range of IP addresses, or the size of the CIDR block." + type = bool + default = false +} + +variable "private_subnet_ipv6_prefixes" { + description = "Assigns IPv6 private subnet id based on the Amazon provided /56 prefix base 10 integer (0-256). Must be of equal length to the corresponding IPv4 subnet list" + type = list + default = [] +} + +variable "public_subnet_ipv6_prefixes" { + description = "Assigns IPv6 public subnet id based on the Amazon provided /56 prefix base 10 integer (0-256). Must be of equal length to the corresponding IPv4 subnet list" + type = list + default = [] +} + +variable "database_subnet_ipv6_prefixes" { + description = "Assigns IPv6 database subnet id based on the Amazon provided /56 prefix base 10 integer (0-256). Must be of equal length to the corresponding IPv4 subnet list" + type = list + default = [] +} + +variable "redshift_subnet_ipv6_prefixes" { + description = "Assigns IPv6 redshift subnet id based on the Amazon provided /56 prefix base 10 integer (0-256). Must be of equal length to the corresponding IPv4 subnet list" + type = list + default = [] +} + +variable "elasticache_subnet_ipv6_prefixes" { + description = "Assigns IPv6 elasticache subnet id based on the Amazon provided /56 prefix base 10 integer (0-256). Must be of equal length to the corresponding IPv4 subnet list" + type = list + default = [] +} + +variable "intra_subnet_ipv6_prefixes" { + description = "Assigns IPv6 intra subnet id based on the Amazon provided /56 prefix base 10 integer (0-256). Must be of equal length to the corresponding IPv4 subnet list" + type = list + default = [] +} + +variable "assign_ipv6_address_on_creation" { + description = "Assign IPv6 address on subnet, must be disabled to change IPv6 CIDRs. This is the IPv6 equivalent of map_public_ip_on_launch" type = bool default = false } +variable "private_subnet_assign_ipv6_address_on_creation" { + description = "Assign IPv6 address on private subnet, must be disabled to change IPv6 CIDRs. This is the IPv6 equivalent of map_public_ip_on_launch" + type = bool + default = null +} + +variable "public_subnet_assign_ipv6_address_on_creation" { + description = "Assign IPv6 address on public subnet, must be disabled to change IPv6 CIDRs. This is the IPv6 equivalent of map_public_ip_on_launch" + type = bool + default = null +} + +variable "database_subnet_assign_ipv6_address_on_creation" { + description = "Assign IPv6 address on database subnet, must be disabled to change IPv6 CIDRs. This is the IPv6 equivalent of map_public_ip_on_launch" + type = bool + default = null +} + +variable "redshift_subnet_assign_ipv6_address_on_creation" { + description = "Assign IPv6 address on redshift subnet, must be disabled to change IPv6 CIDRs. This is the IPv6 equivalent of map_public_ip_on_launch" + type = bool + default = null +} + +variable "elasticache_subnet_assign_ipv6_address_on_creation" { + description = "Assign IPv6 address on elasticache subnet, must be disabled to change IPv6 CIDRs. This is the IPv6 equivalent of map_public_ip_on_launch" + type = bool + default = null +} + +variable "intra_subnet_assign_ipv6_address_on_creation" { + description = "Assign IPv6 address on intra subnet, must be disabled to change IPv6 CIDRs. This is the IPv6 equivalent of map_public_ip_on_launch" + type = bool + default = null +} + variable "secondary_cidr_blocks" { description = "List of secondary CIDR blocks to associate with the VPC to extend the IP Address pool" type = list(string)