diff --git a/modules/net-vpc/README.md b/modules/net-vpc/README.md index 143816ca..4b8c4f8d 100644 --- a/modules/net-vpc/README.md +++ b/modules/net-vpc/README.md @@ -19,6 +19,7 @@ This module allows creation and management of VPC networks including subnetworks - [Custom Routes](#custom-routes) - [Private Google Access routes](#private-google-access-routes) - [Allow Firewall Policy to be evaluated before Firewall Rules](#allow-firewall-policy-to-be-evaluated-before-firewall-rules) + - [IPv6](#ipv6) - [Variables](#variables) - [Outputs](#outputs) @@ -475,13 +476,47 @@ module "vpc" { } # tftest modules=1 resources=5 inventory=firewall_policy_enforcement_order.yaml ``` + +### IPv6 + +A non-overlapping private IPv6 address space can be configured for the VPC via the `ipv6_config` variable. If an internal range is not specified, a unique /48 ULA prefix from the `fd20::/20` range is assigned. + +```hcl +module "vpc" { + source = "./fabric/modules/net-vpc" + project_id = "my-project" + name = "my-network" + ipv6_config = { + # internal_range is optional + enable_ula_internal = true + internal_range = "fd20:6b2:27e5:0:0:0:0:0/48" + } + subnets = [ + { + ip_cidr_range = "10.0.0.0/24" + name = "test" + region = "europe-west1" + ipv6 = {} + }, + { + ip_cidr_range = "10.0.1.0/24" + name = "test" + region = "europe-west3" + ipv6 = { + access_type = "EXTERNAL" + } + } + ] +} +# tftest modules=1 resources=5 inventory=ipv6.yaml +``` ## Variables | name | description | type | required | default | |---|---|:---:|:---:|:---:| -| [name](variables.tf#L83) | The name of the network being created. | string | ✓ | | -| [project_id](variables.tf#L99) | The ID of the project where this VPC will be created. | string | ✓ | | +| [name](variables.tf#L93) | The name of the network being created. | string | ✓ | | +| [project_id](variables.tf#L109) | The ID of the project where this VPC will be created. | string | ✓ | | | [auto_create_subnetworks](variables.tf#L17) | Set to true to create an auto mode subnet, defaults to custom mode. | bool | | false | | [create_googleapis_routes](variables.tf#L23) | Toggle creation of googleapis private/restricted routes. Disabled when vpc creation is turned off, or when set to null. | object({…}) | | {} | | [data_folder](variables.tf#L34) | An optional folder containing the subnet configurations in YaML format. | string | | null | @@ -489,19 +524,20 @@ module "vpc" { | [description](variables.tf#L46) | An optional description of this resource (triggers recreation on change). | string | | "Terraform-managed." | | [dns_policy](variables.tf#L52) | DNS policy setup for the VPC. | object({…}) | | null | | [firewall_policy_enforcement_order](variables.tf#L65) | Order that Firewall Rules and Firewall Policies are evaluated. Can be either 'BEFORE_CLASSIC_FIREWALL' or 'AFTER_CLASSIC_FIREWALL'. | string | | "AFTER_CLASSIC_FIREWALL" | -| [mtu](variables.tf#L77) | Maximum Transmission Unit in bytes. The minimum value for this field is 1460 (the default) and the maximum value is 1500 bytes. | number | | null | -| [peering_config](variables.tf#L88) | VPC peering configuration. | object({…}) | | null | -| [psa_config](variables.tf#L104) | The Private Service Access configuration for Service Networking. | object({…}) | | null | -| [routes](variables.tf#L114) | Network routes, keyed by name. | map(object({…})) | | {} | -| [routing_mode](variables.tf#L135) | The network routing mode (default 'GLOBAL'). | string | | "GLOBAL" | -| [shared_vpc_host](variables.tf#L145) | Enable shared VPC for this project. | bool | | false | -| [shared_vpc_service_projects](variables.tf#L151) | Shared VPC service projects to register with this host. | list(string) | | [] | -| [subnet_iam](variables.tf#L157) | Subnet IAM bindings in {REGION/NAME => {ROLE => [MEMBERS]} format. | map(map(list(string))) | | {} | -| [subnet_iam_additive](variables.tf#L163) | Subnet IAM additive bindings in {REGION/NAME => {ROLE => [MEMBERS]}} format. | map(map(list(string))) | | {} | -| [subnets](variables.tf#L170) | Subnet configuration. | list(object({…})) | | [] | -| [subnets_proxy_only](variables.tf#L195) | List of proxy-only subnets for Regional HTTPS or Internal HTTPS load balancers. Note: Only one proxy-only subnet for each VPC network in each region can be active. | list(object({…})) | | [] | -| [subnets_psc](variables.tf#L207) | List of subnets for Private Service Connect service producers. | list(object({…})) | | [] | -| [vpc_create](variables.tf#L218) | Create VPC. When set to false, uses a data source to reference existing VPC. | bool | | true | +| [ipv6_config](variables.tf#L77) | Optional IPv6 configuration for this network. | object({…}) | | {} | +| [mtu](variables.tf#L87) | Maximum Transmission Unit in bytes. The minimum value for this field is 1460 (the default) and the maximum value is 1500 bytes. | number | | null | +| [peering_config](variables.tf#L98) | VPC peering configuration. | object({…}) | | null | +| [psa_config](variables.tf#L114) | The Private Service Access configuration for Service Networking. | object({…}) | | null | +| [routes](variables.tf#L124) | Network routes, keyed by name. | map(object({…})) | | {} | +| [routing_mode](variables.tf#L145) | The network routing mode (default 'GLOBAL'). | string | | "GLOBAL" | +| [shared_vpc_host](variables.tf#L155) | Enable shared VPC for this project. | bool | | false | +| [shared_vpc_service_projects](variables.tf#L161) | Shared VPC service projects to register with this host. | list(string) | | [] | +| [subnet_iam](variables.tf#L167) | Subnet IAM bindings in {REGION/NAME => {ROLE => [MEMBERS]} format. | map(map(list(string))) | | {} | +| [subnet_iam_additive](variables.tf#L173) | Subnet IAM additive bindings in {REGION/NAME => {ROLE => [MEMBERS]}} format. | map(map(list(string))) | | {} | +| [subnets](variables.tf#L180) | Subnet configuration. | list(object({…})) | | [] | +| [subnets_proxy_only](variables.tf#L206) | List of proxy-only subnets for Regional HTTPS or Internal HTTPS load balancers. Note: Only one proxy-only subnet for each VPC network in each region can be active. | list(object({…})) | | [] | +| [subnets_psc](variables.tf#L218) | List of subnets for Private Service Connect service producers. | list(object({…})) | | [] | +| [vpc_create](variables.tf#L229) | Create VPC. When set to false, uses a data source to reference existing VPC. | bool | | true | ## Outputs @@ -509,16 +545,18 @@ module "vpc" { |---|---|:---:| | [bindings](outputs.tf#L17) | Subnet IAM bindings. | | | [id](outputs.tf#L22) | Fully qualified network id. | | -| [name](outputs.tf#L34) | Network name. | | -| [network](outputs.tf#L46) | Network resource. | | -| [project_id](outputs.tf#L58) | Project ID containing the network. Use this when you need to create resources *after* the VPC is fully set up (e.g. subnets created, shared VPC service projects attached, Private Service Networking configured). | | -| [self_link](outputs.tf#L71) | Network self link. | | -| [subnet_ids](outputs.tf#L83) | Map of subnet IDs keyed by name. | | -| [subnet_ips](outputs.tf#L88) | Map of subnet address ranges keyed by name. | | -| [subnet_regions](outputs.tf#L95) | Map of subnet regions keyed by name. | | -| [subnet_secondary_ranges](outputs.tf#L102) | Map of subnet secondary ranges keyed by name. | | -| [subnet_self_links](outputs.tf#L113) | Map of subnet self links keyed by name. | | -| [subnets](outputs.tf#L118) | Subnet resources. | | -| [subnets_proxy_only](outputs.tf#L123) | L7 ILB or L7 Regional LB subnet resources. | | -| [subnets_psc](outputs.tf#L128) | Private Service Connect subnet resources. | | +| [internal_ipv6_range](outputs.tf#L34) | ULA range. | | +| [name](outputs.tf#L39) | Network name. | | +| [network](outputs.tf#L51) | Network resource. | | +| [project_id](outputs.tf#L63) | Project ID containing the network. Use this when you need to create resources *after* the VPC is fully set up (e.g. subnets created, shared VPC service projects attached, Private Service Networking configured). | | +| [self_link](outputs.tf#L76) | Network self link. | | +| [subnet_ids](outputs.tf#L88) | Map of subnet IDs keyed by name. | | +| [subnet_ips](outputs.tf#L93) | Map of subnet address ranges keyed by name. | | +| [subnet_ipv6_external_prefixes](outputs.tf#L100) | Map of subnet external IPv6 prefixes keyed by name. | | +| [subnet_regions](outputs.tf#L108) | Map of subnet regions keyed by name. | | +| [subnet_secondary_ranges](outputs.tf#L115) | Map of subnet secondary ranges keyed by name. | | +| [subnet_self_links](outputs.tf#L126) | Map of subnet self links keyed by name. | | +| [subnets](outputs.tf#L131) | Subnet resources. | | +| [subnets_proxy_only](outputs.tf#L136) | L7 ILB or L7 Regional LB subnet resources. | | +| [subnets_psc](outputs.tf#L141) | Private Service Connect subnet resources. | | diff --git a/modules/net-vpc/main.tf b/modules/net-vpc/main.tf index 60dcd6a9..7c7ee564 100644 --- a/modules/net-vpc/main.tf +++ b/modules/net-vpc/main.tf @@ -43,6 +43,8 @@ resource "google_compute_network" "network" { mtu = var.mtu routing_mode = var.routing_mode network_firewall_policy_enforcement_order = var.firewall_policy_enforcement_order + enable_ula_internal_ipv6 = var.ipv6_config.enable_ula_internal + internal_ipv6_range = var.ipv6_config.internal_range } resource "google_compute_network_peering" "local" { diff --git a/modules/net-vpc/outputs.tf b/modules/net-vpc/outputs.tf index f9f5254f..69c659a2 100644 --- a/modules/net-vpc/outputs.tf +++ b/modules/net-vpc/outputs.tf @@ -31,6 +31,11 @@ output "id" { ] } +output "internal_ipv6_range" { + description = "ULA range." + value = try(local.network.internal_ipv6_range, null) +} + output "name" { description = "Network name." value = local.network.name @@ -92,6 +97,14 @@ output "subnet_ips" { } } +output "subnet_ipv6_external_prefixes" { + description = "Map of subnet external IPv6 prefixes keyed by name." + value = { + for k, v in google_compute_subnetwork.subnetwork : + k => try(v.external_ipv6_prefix, null) + } +} + output "subnet_regions" { description = "Map of subnet regions keyed by name." value = { diff --git a/modules/net-vpc/subnets.tf b/modules/net-vpc/subnets.tf index 5024a2f0..262c22da 100644 --- a/modules/net-vpc/subnets.tf +++ b/modules/net-vpc/subnets.tf @@ -112,6 +112,13 @@ resource "google_compute_subnetwork" "subnetwork" { for name, range in each.value.secondary_ip_ranges : { range_name = name, ip_cidr_range = range } ] + stack_type = ( + try(each.value.ipv6, null) != null ? "IPV4_IPV6" : null + ) + ipv6_access_type = ( + try(each.value.ipv6, null) != null ? each.value.ipv6.access_type : null + ) + # private_ipv6_google_access = try(each.value.ipv6.enable_private_access, null) dynamic "log_config" { for_each = each.value.flow_logs_config != null ? [""] : [] content { diff --git a/modules/net-vpc/variables.tf b/modules/net-vpc/variables.tf index 7bcf3b90..733692d8 100644 --- a/modules/net-vpc/variables.tf +++ b/modules/net-vpc/variables.tf @@ -74,6 +74,16 @@ variable "firewall_policy_enforcement_order" { } } +variable "ipv6_config" { + description = "Optional IPv6 configuration for this network." + type = object({ + enable_ula_internal = optional(bool) + internal_range = optional(string) + }) + nullable = false + default = {} +} + variable "mtu" { description = "Maximum Transmission Unit in bytes. The minimum value for this field is 1460 (the default) and the maximum value is 1500 bytes." type = number @@ -184,8 +194,9 @@ variable "subnets" { metadata_fields = optional(list(string)) })) ipv6 = optional(object({ - access_type = optional(string) - enable_private_access = optional(bool, true) + access_type = optional(string, "INTERNAL") + # this field is marked for internal use in the API documentation + # enable_private_access = optional(string) })) secondary_ip_ranges = optional(map(string)) })) diff --git a/tests/modules/net_vpc/examples/ipv6.yaml b/tests/modules/net_vpc/examples/ipv6.yaml new file mode 100644 index 00000000..3d98c45d --- /dev/null +++ b/tests/modules/net_vpc/examples/ipv6.yaml @@ -0,0 +1,85 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +values: + module.vpc.google_compute_network.network[0]: + auto_create_subnetworks: false + delete_default_routes_on_create: false + description: Terraform-managed. + enable_ula_internal_ipv6: true + internal_ipv6_range: fd20:6b2:27e5:0:0:0:0:0/48 + name: my-network + network_firewall_policy_enforcement_order: AFTER_CLASSIC_FIREWALL + project: my-project + routing_mode: GLOBAL + timeouts: null + module.vpc.google_compute_route.gateway["private-googleapis"]: + description: Terraform-managed. + dest_range: 199.36.153.8/30 + name: my-network-private-googleapis + next_hop_gateway: default-internet-gateway + next_hop_ilb: null + next_hop_instance: null + next_hop_vpn_tunnel: null + priority: 1000 + project: my-project + tags: null + timeouts: null + module.vpc.google_compute_route.gateway["restricted-googleapis"]: + description: Terraform-managed. + dest_range: 199.36.153.4/30 + name: my-network-restricted-googleapis + next_hop_gateway: default-internet-gateway + next_hop_ilb: null + next_hop_instance: null + next_hop_vpn_tunnel: null + priority: 1000 + project: my-project + tags: null + timeouts: null + module.vpc.google_compute_subnetwork.subnetwork["europe-west1/test"]: + description: Terraform-managed. + ip_cidr_range: 10.0.0.0/24 + ipv6_access_type: INTERNAL + log_config: [] + name: test + private_ip_google_access: true + project: my-project + region: europe-west1 + role: null + secondary_ip_range: [] + stack_type: IPV4_IPV6 + timeouts: null + module.vpc.google_compute_subnetwork.subnetwork["europe-west3/test"]: + description: Terraform-managed. + ip_cidr_range: 10.0.1.0/24 + ipv6_access_type: EXTERNAL + log_config: [] + name: test + private_ip_google_access: true + project: my-project + region: europe-west3 + role: null + secondary_ip_range: [] + stack_type: IPV4_IPV6 + timeouts: null + +counts: + google_compute_network: 1 + google_compute_route: 2 + google_compute_subnetwork: 2 + modules: 1 + resources: 5 + +outputs: {}