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: {}