diff --git a/fast/stages/2-networking-a-simple/data/subnets/dev/dev-gke-nodes.yaml b/fast/stages/2-networking-a-simple/data/subnets/dev/dev-gke-nodes.yaml
index afc7122b0..338e17ab0 100644
--- a/fast/stages/2-networking-a-simple/data/subnets/dev/dev-gke-nodes.yaml
+++ b/fast/stages/2-networking-a-simple/data/subnets/dev/dev-gke-nodes.yaml
@@ -7,5 +7,7 @@ region: $regions:primary
description: Default subnet for prod gke nodes
ip_cidr_range: 10.68.1.0/24
secondary_ip_ranges:
- pods: 100.68.0.0/16
- services: 100.71.1.0/24
+ pods:
+ ip_cidr_range: 100.68.0.0/16
+ services:
+ ip_cidr_range: 100.71.1.0/24
diff --git a/fast/stages/2-networking-b-nva/data/subnets/dev/dev-dataplatform.yaml b/fast/stages/2-networking-b-nva/data/subnets/dev/dev-dataplatform.yaml
index dccb62d09..76ace5082 100644
--- a/fast/stages/2-networking-b-nva/data/subnets/dev/dev-dataplatform.yaml
+++ b/fast/stages/2-networking-b-nva/data/subnets/dev/dev-dataplatform.yaml
@@ -7,5 +7,7 @@ region: $regions:primary
description: Default subnet for dev Data Platform
ip_cidr_range: 10.68.2.0/24
secondary_ip_ranges:
- pods: 100.69.0.0/16
- services: 100.71.2.0/24
+ pods:
+ ip_cidr_range: 100.69.0.0/16
+ services:
+ ip_cidr_range: 100.71.2.0/24
diff --git a/fast/stages/2-networking-b-nva/data/subnets/dev/dev-gke-nodes.yaml b/fast/stages/2-networking-b-nva/data/subnets/dev/dev-gke-nodes.yaml
index afc7122b0..338e17ab0 100644
--- a/fast/stages/2-networking-b-nva/data/subnets/dev/dev-gke-nodes.yaml
+++ b/fast/stages/2-networking-b-nva/data/subnets/dev/dev-gke-nodes.yaml
@@ -7,5 +7,7 @@ region: $regions:primary
description: Default subnet for prod gke nodes
ip_cidr_range: 10.68.1.0/24
secondary_ip_ranges:
- pods: 100.68.0.0/16
- services: 100.71.1.0/24
+ pods:
+ ip_cidr_range: 100.68.0.0/16
+ services:
+ ip_cidr_range: 100.71.1.0/24
diff --git a/fast/stages/2-networking-c-separate-envs/data/subnets/dev/dev-dataplatform.yaml b/fast/stages/2-networking-c-separate-envs/data/subnets/dev/dev-dataplatform.yaml
index dccb62d09..76ace5082 100644
--- a/fast/stages/2-networking-c-separate-envs/data/subnets/dev/dev-dataplatform.yaml
+++ b/fast/stages/2-networking-c-separate-envs/data/subnets/dev/dev-dataplatform.yaml
@@ -7,5 +7,7 @@ region: $regions:primary
description: Default subnet for dev Data Platform
ip_cidr_range: 10.68.2.0/24
secondary_ip_ranges:
- pods: 100.69.0.0/16
- services: 100.71.2.0/24
+ pods:
+ ip_cidr_range: 100.69.0.0/16
+ services:
+ ip_cidr_range: 100.71.2.0/24
diff --git a/fast/stages/2-networking-c-separate-envs/data/subnets/dev/dev-gke-nodes.yaml b/fast/stages/2-networking-c-separate-envs/data/subnets/dev/dev-gke-nodes.yaml
index afc7122b0..338e17ab0 100644
--- a/fast/stages/2-networking-c-separate-envs/data/subnets/dev/dev-gke-nodes.yaml
+++ b/fast/stages/2-networking-c-separate-envs/data/subnets/dev/dev-gke-nodes.yaml
@@ -7,5 +7,7 @@ region: $regions:primary
description: Default subnet for prod gke nodes
ip_cidr_range: 10.68.1.0/24
secondary_ip_ranges:
- pods: 100.68.0.0/16
- services: 100.71.1.0/24
+ pods:
+ ip_cidr_range: 100.68.0.0/16
+ services:
+ ip_cidr_range: 100.71.1.0/24
diff --git a/modules/gke-hub/README.md b/modules/gke-hub/README.md
index 8c703a4ed..3bf643b48 100644
--- a/modules/gke-hub/README.md
+++ b/modules/gke-hub/README.md
@@ -39,8 +39,8 @@ module "vpc" {
name = "cluster-1"
region = "europe-west1"
secondary_ip_range = {
- pods = "10.1.0.0/16"
- services = "10.2.0.0/24"
+ pods = { ip_cidr_range = "10.1.0.0/16" }
+ services = { ip_cidr_range = "10.2.0.0/24" }
}
}]
}
@@ -142,8 +142,8 @@ module "vpc" {
name = "subnet-cluster-1"
region = "europe-west1"
secondary_ip_ranges = {
- pods = "10.1.0.0/16"
- services = "10.2.0.0/24"
+ pods = { ip_cidr_range = "10.1.0.0/16" }
+ services = { ip_cidr_range = "10.2.0.0/24" }
}
},
{
@@ -151,8 +151,8 @@ module "vpc" {
name = "subnet-cluster-2"
region = "europe-west4"
secondary_ip_ranges = {
- pods = "10.3.0.0/16"
- services = "10.4.0.0/24"
+ pods = { ip_cidr_range = "10.3.0.0/16" }
+ services = { ip_cidr_range = "10.4.0.0/24" }
}
},
{
diff --git a/modules/net-vpc/README.md b/modules/net-vpc/README.md
index 59fd876fb..8309ec6c4 100644
--- a/modules/net-vpc/README.md
+++ b/modules/net-vpc/README.md
@@ -24,6 +24,10 @@ This module allows creation and management of VPC networks including subnetworks
- [Allow Firewall Policy to be evaluated before Firewall Rules](#allow-firewall-policy-to-be-evaluated-before-firewall-rules)
- [IPv6](#ipv6)
- [IPv6-Only and IP Collections](#ipv6-only-and-ip-collections)
+ - [Internal Ranges](#internal-ranges)
+ - [Basic Internal Range Configuration](#basic-internal-range-configuration)
+ - [Subnets with Internal Ranges](#subnets-with-internal-ranges)
+ - [Internal Range Factory](#internal-range-factory)
- [Variables](#variables)
- [Outputs](#outputs)
@@ -41,8 +45,8 @@ module "vpc" {
name = "production"
region = "europe-west1"
secondary_ip_ranges = {
- pods = "172.16.0.0/20"
- services = "192.168.0.0/24"
+ pods = { ip_cidr_range = "172.16.0.0/20" }
+ services = { ip_cidr_range = "192.168.0.0/24" }
}
},
{
@@ -83,8 +87,8 @@ module "vpc" {
region = "europe-west1"
ip_cidr_range = "10.0.2.0/24"
secondary_ip_ranges = {
- a = "192.168.0.0/24"
- b = "192.168.1.0/24"
+ a = { ip_cidr_range = "192.168.0.0/24" }
+ b = { ip_cidr_range = "192.168.1.0/24" }
}
},
# enable flow logs
@@ -221,8 +225,8 @@ module "vpc-host" {
name = "subnet-1"
region = "europe-west1"
secondary_ip_ranges = {
- pods = "172.16.0.0/20"
- services = "192.168.0.0/24"
+ pods = { ip_cidr_range = "172.16.0.0/20" }
+ services = { ip_cidr_range = "192.168.0.0/24" }
}
iam = {
"roles/compute.networkUser" = [
@@ -522,7 +526,8 @@ iam:
- serviceAccount:fbz@prj.iam.gserviceaccount.com
- user:foobar@example.com
secondary_ip_ranges: # map of secondary ip ranges
- secondary-range-a: 192.168.0.0/24
+ secondary-range-a:
+ ip_cidr_range: 192.168.0.0/24
flow_logs_config: # enable, set to empty map to use defaults
aggregation_interval: "INTERVAL_5_SEC"
flow_sampling: 0.5
@@ -666,8 +671,8 @@ module "vpc" {
name = "production"
region = "europe-west1"
secondary_ip_ranges = {
- pods = "172.16.0.0/20"
- services = "192.168.0.0/24"
+ pods = { ip_cidr_range = "172.16.0.0/20" }
+ services = { ip_cidr_range = "192.168.0.0/24" }
}
},
{
@@ -716,12 +721,7 @@ module "vpc" {
### IPv6-Only and IP Collections
-An IPv6-only subnetwork can be specified by setting `ipv6_only` to `true` and
-setting `ip_cidr_range` to `null`. An IP Collection may be specified with
-`ip_collection` and a
-[reference](https://cloud.google.com/compute/docs/reference/rest/v1/subnetworks/insert)
-to a collection source, like a PublicDelegatedPrefix (PDP) for BYOIPv6. The PDP
-must be a sub-PDP in `EXTERNAL_IPV6_SUBNETWORK_CREATION` mode.
+An IPv6-only subnetwork can be specified by setting `ipv6_only` to `true` and setting `ip_cidr_range` to `null`. An IP Collection may be specified with `ip_collection` and a [reference](https://cloud.google.com/compute/docs/reference/rest/v1/subnetworks/insert) to a collection source, like a PublicDelegatedPrefix (PDP) for BYOIPv6. The PDP must be a sub-PDP in `EXTERNAL_IPV6_SUBNETWORK_CREATION` mode.
```hcl
module "vpc" {
@@ -754,36 +754,177 @@ module "vpc" {
}
# tftest modules=1 resources=6 inventory=ipv6_only.yaml
```
+
+### Internal Ranges
+
+Google Cloud [Internal Ranges](https://cloud.google.com/vpc/docs/create-use-internal-ranges) provide advanced IPAM (IP Address Management) capabilities for VPC networks. Internal ranges represent private address ranges with specific behavioral characteristics such as usage and peering behavior. The module supports creating internal ranges directly or through factory configurations, and integrating them with subnet creation.
+
+#### Basic Internal Range Configuration
+
+```hcl
+module "vpc" {
+ source = "./fabric/modules/net-vpc"
+ project_id = var.project_id
+ name = "my-network"
+ internal_ranges = [
+ {
+ name = "range1"
+ usage = "FOR_VPC"
+ peering = "FOR_SELF"
+ ip_cidr_range = "10.0.0.0/16"
+ },
+ {
+ name = "range2"
+ usage = "FOR_VPC"
+ peering = "FOR_SELF"
+ prefix_length = 24
+ target_cidr_range = ["10.1.0.0/16"]
+ description = "Auto-allocated secondary range"
+ }
+ ]
+}
+# tftest inventory=internal-ranges.yaml
+```
+
+#### Subnets with Internal Ranges
+
+Subnets can reference internal ranges instead of specifying explicit CIDR ranges, enabling centralized IP management:
+
+```hcl
+module "vpc" {
+ source = "./fabric/modules/net-vpc"
+ project_id = var.project_id
+ name = "my-network"
+ internal_ranges = [
+ {
+ name = "subnet-range"
+ usage = "FOR_VPC"
+ peering = "FOR_SELF"
+ ip_cidr_range = "10.0.1.0/24"
+ },
+ {
+ name = "pods-range"
+ usage = "FOR_VPC"
+ peering = "FOR_SELF"
+ ip_cidr_range = "10.1.0.0/16"
+ },
+ {
+ name = "services-range"
+ usage = "FOR_VPC"
+ peering = "FOR_SELF"
+ prefix_length = 20
+ target_cidr_range = ["10.2.0.0/16"]
+ }
+ ]
+ subnets = [
+ {
+ name = "production"
+ region = "europe-west1"
+ reserved_internal_range = "subnet-range"
+ secondary_ip_ranges = {
+ pods = {
+ reserved_internal_range = "pods-range"
+ }
+ services = {
+ reserved_internal_range = "services-range"
+ }
+ # Mixed configuration: some ranges use internal ranges, others use CIDR
+ traditional = {
+ ip_cidr_range = "192.168.0.0/24"
+ }
+ }
+ }
+ ]
+}
+# tftest inventory=subnets-internal-ranges.yaml
+```
+
+#### Internal Range Factory
+
+Internal ranges can be defined using YAML factory files, similar to the subnet factory:
+
+```hcl
+module "vpc" {
+ source = "./fabric/modules/net-vpc"
+ project_id = var.project_id
+ name = "my-network"
+ factories_config = {
+ internal_ranges_folder = "config/internal-ranges"
+ subnets_folder = "config/subnets"
+ }
+}
+# tftest files=subnet,subnet-range,pods-range,services-range inventory=subnets-internal-ranges.yaml
+```
+
+```yaml
+usage: FOR_VPC
+peering: FOR_SELF
+ip_cidr_range: "10.0.1.0/24"
+# tftest-file id=subnet-range path=config/internal-ranges/subnet-range.yaml schema=internal-range.schema.json
+```
+
+```yaml
+usage: FOR_VPC
+peering: FOR_SELF
+ip_cidr_range: "10.1.0.0/16"
+
+# tftest-file id=pods-range path=config/internal-ranges/pods-range.yaml schema=internal-range.schema.json
+```
+
+```yaml
+usage: FOR_VPC
+peering: FOR_SELF
+prefix_length: 20
+target_cidr_range:
+ - "10.2.0.0/16"
+
+# tftest-file id=services-range path=config/internal-ranges/services-range.yaml schema=internal-range.schema.json
+```
+
+```yaml
+region: europe-west1
+reserved_internal_range: subnet-range
+secondary_ip_ranges:
+ pods:
+ reserved_internal_range: pods-range
+ services:
+ reserved_internal_range: services-range
+ traditional:
+ ip_cidr_range: "192.168.0.0/24"
+
+# tftest-file id=subnet path=config/subnets/production.yaml schema=subnet.schema.json
+```
## Variables
| name | description | type | required | default |
|---|---|:---:|:---:|:---:|
-| [name](variables.tf#L106) | The name of the network being created. | string | ✓ | |
-| [project_id](variables.tf#L183) | The ID of the project where this VPC will be created. | string | ✓ | |
+| [name](variables.tf#L171) | The name of the network being created. | string | ✓ | |
+| [project_id](variables.tf#L248) | 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 |
| [context](variables.tf#L23) | Context-specific interpolations. | object({…}) | | {} |
| [create_googleapis_routes](variables.tf#L32) | Toggle creation of googleapis private/restricted routes. Disabled when vpc creation is turned off, or when set to null. | object({…}) | | {} |
| [delete_default_routes_on_create](variables.tf#L45) | Set to true to delete the default routes at creation time. | bool | | false |
| [description](variables.tf#L51) | An optional description of this resource (triggers recreation on change). | string | | "Terraform-managed." |
| [dns_policy](variables.tf#L57) | DNS policy setup for the VPC. | object({…}) | | null |
-| [factories_config](variables.tf#L70) | Paths to data files and folders that enable factory functionality. | object({…}) | | {} |
-| [firewall_policy_enforcement_order](variables.tf#L78) | Order that Firewall Rules and Firewall Policies are evaluated. Can be either 'BEFORE_CLASSIC_FIREWALL' or 'AFTER_CLASSIC_FIREWALL'. | string | | "AFTER_CLASSIC_FIREWALL" |
-| [ipv6_config](variables.tf#L90) | Optional IPv6 configuration for this network. | object({…}) | | {} |
-| [mtu](variables.tf#L100) | Maximum Transmission Unit in bytes. The minimum value for this field is 1460 (the default) and the maximum value is 1500 bytes. | number | | null |
-| [network_attachments](variables.tf#L111) | PSC network attachments, names as keys. | map(object({…})) | | {} |
-| [peering_config](variables.tf#L124) | VPC peering configuration. | object({…}) | | null |
-| [policy_based_routes](variables.tf#L135) | Policy based routes, keyed by name. | map(object({…})) | | {} |
-| [psa_configs](variables.tf#L188) | The Private Service Access configuration. | list(object({…})) | | [] |
-| [routes](variables.tf#L219) | Network routes, keyed by name. | map(object({…})) | | {} |
-| [routing_mode](variables.tf#L240) | The network routing mode (default 'GLOBAL'). | string | | "GLOBAL" |
-| [shared_vpc_host](variables.tf#L250) | Enable shared VPC for this project. | bool | | false |
-| [shared_vpc_service_projects](variables.tf#L256) | Shared VPC service projects to register with this host. | list(string) | | [] |
-| [subnets](variables.tf#L262) | Subnet configuration. | list(object({…})) | | [] |
-| [subnets_private_nat](variables.tf#L311) | List of private NAT subnets. | list(object({…})) | | [] |
-| [subnets_proxy_only](variables.tf#L323) | 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#L357) | List of subnets for Private Service Connect service producers. | list(object({…})) | | [] |
-| [vpc_reuse](variables.tf#L389) | Reuse existing VPC if not null. If the network_id number is not passed in, a data source is used. | object({…}) | | null |
+| [factories_config](variables.tf#L70) | Paths to data files and folders that enable factory functionality. | object({…}) | | {} |
+| [firewall_policy_enforcement_order](variables.tf#L79) | Order that Firewall Rules and Firewall Policies are evaluated. Can be either 'BEFORE_CLASSIC_FIREWALL' or 'AFTER_CLASSIC_FIREWALL'. | string | | "AFTER_CLASSIC_FIREWALL" |
+| [internal_ranges](variables.tf#L91) | Internal range configuration for IPAM operations within the VPC network. | list(object({…})) | | [] |
+| [ipv6_config](variables.tf#L155) | Optional IPv6 configuration for this network. | object({…}) | | {} |
+| [mtu](variables.tf#L165) | Maximum Transmission Unit in bytes. The minimum value for this field is 1460 (the default) and the maximum value is 1500 bytes. | number | | null |
+| [network_attachments](variables.tf#L176) | PSC network attachments, names as keys. | map(object({…})) | | {} |
+| [peering_config](variables.tf#L189) | VPC peering configuration. | object({…}) | | null |
+| [policy_based_routes](variables.tf#L200) | Policy based routes, keyed by name. | map(object({…})) | | {} |
+| [psa_configs](variables.tf#L253) | The Private Service Access configuration. | list(object({…})) | | [] |
+| [routes](variables.tf#L284) | Network routes, keyed by name. | map(object({…})) | | {} |
+| [routing_mode](variables.tf#L305) | The network routing mode (default 'GLOBAL'). | string | | "GLOBAL" |
+| [shared_vpc_host](variables.tf#L315) | Enable shared VPC for this project. | bool | | false |
+| [shared_vpc_service_projects](variables.tf#L321) | Shared VPC service projects to register with this host. | list(string) | | [] |
+| [subnets](variables.tf#L327) | Subnet configuration. | list(object({…})) | | [] |
+| [subnets_private_nat](variables.tf#L407) | List of private NAT subnets. | list(object({…})) | | [] |
+| [subnets_proxy_only](variables.tf#L419) | 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#L453) | List of subnets for Private Service Connect service producers. | list(object({…})) | | [] |
+| [vpc_reuse](variables.tf#L485) | Reuse existing VPC if not null. If the network_id number is not passed in, a data source is used. | object({…}) | | null |
## Outputs
@@ -791,19 +932,22 @@ module "vpc" {
|---|---|:---:|
| [id](outputs.tf#L17) | Fully qualified network id. | |
| [internal_ipv6_range](outputs.tf#L29) | ULA range. | |
-| [name](outputs.tf#L34) | Network name. | |
-| [network](outputs.tf#L46) | Network resource. | |
-| [network_attachment_ids](outputs.tf#L58) | IDs of network attachments. | |
-| [project_id](outputs.tf#L66) | 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#L79) | Network self link. | |
-| [subnet_ids](outputs.tf#L91) | Map of subnet IDs keyed by name. | |
-| [subnet_ips](outputs.tf#L100) | Map of subnet address ranges keyed by name. | |
-| [subnet_ipv6_external_prefixes](outputs.tf#L107) | Map of subnet external IPv6 prefixes keyed by name. | |
-| [subnet_regions](outputs.tf#L115) | Map of subnet regions keyed by name. | |
-| [subnet_secondary_ranges](outputs.tf#L122) | Map of subnet secondary ranges keyed by name. | |
-| [subnet_self_links](outputs.tf#L133) | Map of subnet self links keyed by name. | |
-| [subnets](outputs.tf#L142) | Subnet resources. | |
-| [subnets_private_nat](outputs.tf#L151) | Private NAT subnet resources. | |
-| [subnets_proxy_only](outputs.tf#L156) | L7 ILB or L7 Regional LB subnet resources. | |
-| [subnets_psc](outputs.tf#L161) | Private Service Connect subnet resources. | |
+| [internal_range_ids](outputs.tf#L34) | Map of internal range IDs keyed by name. | |
+| [internal_range_ip_cidr_ranges](outputs.tf#L39) | Map of internal range IP CIDR ranges keyed by name. | |
+| [internal_ranges](outputs.tf#L46) | Internal range resources. | |
+| [name](outputs.tf#L51) | Network name. | |
+| [network](outputs.tf#L63) | Network resource. | |
+| [network_attachment_ids](outputs.tf#L75) | IDs of network attachments. | |
+| [project_id](outputs.tf#L83) | 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#L96) | Network self link. | |
+| [subnet_ids](outputs.tf#L108) | Map of subnet IDs keyed by name. | |
+| [subnet_ips](outputs.tf#L117) | Map of subnet address ranges keyed by name. | |
+| [subnet_ipv6_external_prefixes](outputs.tf#L124) | Map of subnet external IPv6 prefixes keyed by name. | |
+| [subnet_regions](outputs.tf#L132) | Map of subnet regions keyed by name. | |
+| [subnet_secondary_ranges](outputs.tf#L139) | Map of subnet secondary ranges keyed by name. | |
+| [subnet_self_links](outputs.tf#L150) | Map of subnet self links keyed by name. | |
+| [subnets](outputs.tf#L159) | Subnet resources. | |
+| [subnets_private_nat](outputs.tf#L168) | Private NAT subnet resources. | |
+| [subnets_proxy_only](outputs.tf#L173) | L7 ILB or L7 Regional LB subnet resources. | |
+| [subnets_psc](outputs.tf#L178) | Private Service Connect subnet resources. | |
diff --git a/modules/net-vpc/internal-ranges.tf b/modules/net-vpc/internal-ranges.tf
new file mode 100644
index 000000000..2304919d4
--- /dev/null
+++ b/modules/net-vpc/internal-ranges.tf
@@ -0,0 +1,100 @@
+/**
+ * Copyright 2024 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.
+ */
+
+# tfdoc:file:description Internal range resources.
+
+locals {
+ _internal_ranges_factory_data_raw = {
+ for f in try(fileset(local._internal_ranges_factory_path, "**/*.yaml"), []) :
+ trimsuffix(basename(f), ".yaml") => yamldecode(file("${local._internal_ranges_factory_path}/${f}"))
+ }
+ _internal_ranges_factory_data = {
+ for k, v in local._internal_ranges_factory_data_raw : k => merge(v, {
+ name = try(v.name, k)
+ })
+ }
+ _internal_ranges_factory_path = try(pathexpand(var.factories_config.internal_ranges_folder), null)
+ _factory_internal_ranges = {
+ for k, v in local._internal_ranges_factory_data :
+ try(v.name, k) => {
+ description = try(v.description, null)
+ ip_cidr_range = try(v.ip_cidr_range, null)
+ labels = try(v.labels, {})
+ name = try(v.name, k)
+ network = try(v.network, local.network.id)
+ usage = v.usage
+ peering = v.peering
+ prefix_length = try(v.prefix_length, null)
+ target_cidr_range = try(v.target_cidr_range, null)
+ exclude_cidr_ranges = try(v.exclude_cidr_ranges, null)
+ overlaps = try(v.overlaps, null)
+ immutable = try(v.immutable, null)
+ allocation_options = !can(v.allocation_options) ? null : {
+ allocation_strategy = try(v.allocation_options.allocation_strategy, null)
+ first_available_ranges_lookup_size = try(v.allocation_options.first_available_ranges_lookup_size, null)
+ }
+ migration = !can(v.migration) ? null : {
+ source = v.migration.source
+ target = v.migration.target
+ }
+ }
+ }
+
+ internal_ranges = merge(
+ { for r in var.internal_ranges : r.name => r },
+ local._factory_internal_ranges
+ )
+
+ internal_ranges_ids = {
+ for k, v in google_network_connectivity_internal_range.internal_range :
+ k => v.id
+ }
+}
+
+resource "google_network_connectivity_internal_range" "internal_range" {
+ provider = google-beta
+ for_each = local.internal_ranges
+ project = var.project_id
+ name = each.value.name
+ network = local.network.id
+
+ description = each.value.description
+ ip_cidr_range = each.value.ip_cidr_range
+ labels = each.value.labels
+ usage = each.value.usage
+ peering = each.value.peering
+ prefix_length = each.value.prefix_length
+ target_cidr_range = each.value.target_cidr_range
+ exclude_cidr_ranges = each.value.exclude_cidr_ranges
+ overlaps = each.value.overlaps
+ immutable = each.value.immutable
+
+ dynamic "allocation_options" {
+ for_each = each.value.allocation_options != null ? [""] : []
+ content {
+ allocation_strategy = each.value.allocation_options.allocation_strategy
+ first_available_ranges_lookup_size = each.value.allocation_options.first_available_ranges_lookup_size
+ }
+ }
+
+ dynamic "migration" {
+ for_each = each.value.migration != null ? [""] : []
+ content {
+ source = each.value.migration.source
+ target = each.value.migration.target
+ }
+ }
+}
diff --git a/modules/net-vpc/outputs.tf b/modules/net-vpc/outputs.tf
index 8184e96d4..1e162ffb7 100644
--- a/modules/net-vpc/outputs.tf
+++ b/modules/net-vpc/outputs.tf
@@ -1,5 +1,5 @@
/**
- * Copyright 2024 Google LLC
+ * Copyright 2025 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,6 +31,23 @@ output "internal_ipv6_range" {
value = try(google_compute_network.network[0].internal_ipv6_range, null)
}
+output "internal_range_ids" {
+ description = "Map of internal range IDs keyed by name."
+ value = { for k, v in google_network_connectivity_internal_range.internal_range : k => v.id }
+}
+
+output "internal_range_ip_cidr_ranges" {
+ description = "Map of internal range IP CIDR ranges keyed by name."
+ value = {
+ for k, v in google_network_connectivity_internal_range.internal_range : k => v.ip_cidr_range
+ }
+}
+
+output "internal_ranges" {
+ description = "Internal range resources."
+ value = { for k, v in google_network_connectivity_internal_range.internal_range : k => v }
+}
+
output "name" {
description = "Network name."
value = local.network.name
diff --git a/modules/net-vpc/schemas/internal-range.schema.json b/modules/net-vpc/schemas/internal-range.schema.json
new file mode 100644
index 000000000..02f8eb938
--- /dev/null
+++ b/modules/net-vpc/schemas/internal-range.schema.json
@@ -0,0 +1,110 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "title": "InternalRange",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "usage",
+ "peering"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of the internal range. If not provided, the filename will be used."
+ },
+ "description": {
+ "type": "string",
+ "description": "An optional description of this internal range."
+ },
+ "labels": {
+ "type": "object",
+ "description": "User-defined labels.",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "ip_cidr_range": {
+ "type": "string",
+ "description": "The IP range that this internal range defines. Note: IPv6 ranges are limited to usage=EXTERNAL_TO_VPC and peering=FOR_SELF. For IPv6 ranges this field is compulsory."
+ },
+ "usage": {
+ "type": "string",
+ "enum": ["FOR_VPC", "EXTERNAL_TO_VPC", "FOR_MIGRATION"],
+ "description": "The type of usage set for this InternalRange."
+ },
+ "peering": {
+ "type": "string",
+ "enum": ["FOR_SELF", "FOR_PEER", "NOT_SHARED"],
+ "description": "The type of peering set for this internal range."
+ },
+ "prefix_length": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 32,
+ "description": "An alternate to ip_cidr_range. Can be set when trying to create a reservation that automatically finds a free range of the given size."
+ },
+ "target_cidr_range": {
+ "type": "array",
+ "description": "Optional. Can be set to narrow down or pick a different address space while searching for a free range.",
+ "items": {
+ "type": "string"
+ }
+ },
+ "exclude_cidr_ranges": {
+ "type": "array",
+ "description": "Optional. List of IP CIDR ranges to be excluded. Only IPv4 CIDR ranges are supported.",
+ "items": {
+ "type": "string"
+ }
+ },
+ "allocation_options": {
+ "type": "object",
+ "description": "Options for automatically allocating a free range with a size given by prefixLength.",
+ "additionalProperties": false,
+ "properties": {
+ "allocation_strategy": {
+ "type": "string",
+ "enum": ["RANDOM", "FIRST_AVAILABLE", "RANDOM_FIRST_N_AVAILABLE", "FIRST_SMALLEST_FITTING"],
+ "description": "Sets the strategy used to automatically find a free range of a size given by prefixLength."
+ },
+ "first_available_ranges_lookup_size": {
+ "type": "integer",
+ "minimum": 1,
+ "description": "Must be set when allocation_strategy is RANDOM_FIRST_N_AVAILABLE, otherwise must remain unset."
+ }
+ }
+ },
+ "overlaps": {
+ "type": "array",
+ "description": "Optional. Types of resources that are allowed to overlap with the current internal range.",
+ "items": {
+ "type": "string",
+ "enum": ["OVERLAP_ROUTE_RANGE", "OVERLAP_EXISTING_SUBNET_RANGE"]
+ }
+ },
+ "migration": {
+ "type": "object",
+ "description": "Specification for migration with source and target resource names.",
+ "additionalProperties": false,
+ "required": ["source", "target"],
+ "properties": {
+ "source": {
+ "type": "string",
+ "description": "Resource path as an URI of the source resource, for example a subnet."
+ },
+ "target": {
+ "type": "string",
+ "description": "Resource path of the target resource. The target project can be different."
+ }
+ }
+ },
+ "immutable": {
+ "type": "boolean",
+ "description": "Immutable ranges cannot have their fields modified, except for labels and description."
+ }
+ },
+ "anyOf": [
+ {"required": ["ip_cidr_range"]},
+ {"required": ["prefix_length"]}
+ ]
+}
diff --git a/modules/net-vpc/schemas/subnet.schema.json b/modules/net-vpc/schemas/subnet.schema.json
index 48f8093c6..6e1095692 100644
--- a/modules/net-vpc/schemas/subnet.schema.json
+++ b/modules/net-vpc/schemas/subnet.schema.json
@@ -4,9 +4,21 @@
"type": "object",
"additionalProperties": false,
"required": [
- "ip_cidr_range",
"region"
],
+ "anyOf": [
+ {"required": ["ip_cidr_range"]},
+ {"required": ["reserved_internal_range"]},
+ {"required": ["ip_collection"]},
+ {
+ "allOf": [
+ {"not": {"required": ["ip_cidr_range"]}},
+ {"not": {"required": ["reserved_internal_range"]}},
+ {"not": {"required": ["ip_collection"]}},
+ {"properties": {"ipv6": {"properties": {"ipv6_only": {"const": true}}}}, "required": ["ipv6"]}
+ ]
+ }
+ ],
"properties": {
"active": {
"type": "boolean"
@@ -50,6 +62,10 @@
"ip_cidr_range": {
"type": "string"
},
+ "reserved_internal_range": {
+ "type": "string",
+ "description": "Name of the internal range to use for this subnet. Mutually exclusive with ip_cidr_range and ip_collection."
+ },
"ipv6": {
"type": "object",
"additionalProperties": false,
@@ -80,7 +96,30 @@
"secondary_ip_ranges": {
"type": "object",
"additionalProperties": {
- "type": "string"
+ "oneOf": [
+ {
+ "type": "string",
+ "description": "IP CIDR range for backward compatibility"
+ },
+ {
+ "type": "object",
+ "additionalProperties": false,
+ "anyOf": [
+ {"required": ["ip_cidr_range"]},
+ {"required": ["reserved_internal_range"]}
+ ],
+ "properties": {
+ "ip_cidr_range": {
+ "type": "string",
+ "description": "IP CIDR range for this secondary range"
+ },
+ "reserved_internal_range": {
+ "type": "string",
+ "description": "Name of the internal range to use for this secondary range"
+ }
+ }
+ }
+ ]
}
},
"iam": {
@@ -189,4 +228,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/modules/net-vpc/subnets.tf b/modules/net-vpc/subnets.tf
index 06f103003..5d3ff70f0 100644
--- a/modules/net-vpc/subnets.tf
+++ b/modules/net-vpc/subnets.tf
@@ -1,5 +1,5 @@
/**
- * Copyright 2024 Google LLC
+ * Copyright 2025 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -34,6 +34,7 @@ locals {
description = try(v.description, null)
enable_private_access = try(v.enable_private_access, true)
allow_subnet_cidr_routes_overlap = try(v.allow_subnet_cidr_routes_overlap, null)
+ reserved_internal_range = try(v.reserved_internal_range, null)
flow_logs_config = can(v.flow_logs_config) ? {
aggregation_interval = try(v.flow_logs_config.aggregation_interval, null)
filter_expression = try(v.flow_logs_config.filter_expression, null)
@@ -42,16 +43,22 @@ locals {
metadata_fields = try(v.flow_logs_config.metadata_fields, null)
} : null
global = try(v.global, false)
- ip_cidr_range = v.ip_cidr_range
+ ip_cidr_range = try(v.ip_cidr_range, null)
ipv6 = !can(v.ipv6) ? null : {
access_type = try(v.ipv6.access_type, "INTERNAL")
ipv6_only = try(v.ipv6.ipv6_only, false)
}
- ip_collection = try(v.ip_collection, null)
- name = try(v.name, k)
- region = v.region_computed
- secondary_ip_ranges = try(v.secondary_ip_ranges, null)
- iam = try(v.iam, {})
+ ip_collection = try(v.ip_collection, null)
+ name = try(v.name, k)
+ region = v.region_computed
+ secondary_ip_ranges = !can(v.secondary_ip_ranges) ? null : {
+ for k2, v2 in v.secondary_ip_ranges :
+ k2 => {
+ ip_cidr_range = try(v2.ip_cidr_range, null)
+ reserved_internal_range = try(v2.reserved_internal_range, null)
+ }
+ }
+ iam = try(v.iam, {})
iam_bindings = !can(v.iam_bindings) ? {} : {
for k2, v2 in v.iam_bindings :
k2 => {
@@ -151,6 +158,11 @@ resource "google_compute_subnetwork" "subnetwork" {
region = each.value.region
ip_cidr_range = try(each.value.ipv6.ipv6_only, false) ? null : each.value.ip_cidr_range
allow_subnet_cidr_routes_overlap = each.value.allow_subnet_cidr_routes_overlap
+ reserved_internal_range = (
+ each.value.reserved_internal_range != null
+ ? "networkconnectivity.googleapis.com/${try(local.internal_ranges_ids[each.value.reserved_internal_range], each.value.reserved_internal_range)}"
+ : null
+ )
description = (
# Set description to an empty string (eg "") to create subnet without a description.
each.value.description == null
@@ -178,7 +190,12 @@ resource "google_compute_subnetwork" "subnetwork" {
for_each = each.value.secondary_ip_ranges == null ? {} : each.value.secondary_ip_ranges
content {
range_name = secondary_ip_range.key
- ip_cidr_range = secondary_ip_range.value
+ ip_cidr_range = try(secondary_ip_range.value.ip_cidr_range, secondary_ip_range.value)
+ reserved_internal_range = (
+ try(secondary_ip_range.value.reserved_internal_range, null) != null
+ ? "networkconnectivity.googleapis.com/${try(local.internal_ranges_ids[secondary_ip_range.value.reserved_internal_range], secondary_ip_range.value.reserved_internal_range)}"
+ : null
+ )
}
}
dynamic "log_config" {
diff --git a/modules/net-vpc/variables.tf b/modules/net-vpc/variables.tf
index 4b44c6ac1..646a75212 100644
--- a/modules/net-vpc/variables.tf
+++ b/modules/net-vpc/variables.tf
@@ -1,5 +1,5 @@
/**
- * Copyright 2024 Google LLC
+ * Copyright 2025 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -70,7 +70,8 @@ variable "dns_policy" {
variable "factories_config" {
description = "Paths to data files and folders that enable factory functionality."
type = object({
- subnets_folder = optional(string)
+ subnets_folder = optional(string)
+ internal_ranges_folder = optional(string)
})
default = {}
}
@@ -87,6 +88,70 @@ variable "firewall_policy_enforcement_order" {
}
}
+variable "internal_ranges" {
+ description = "Internal range configuration for IPAM operations within the VPC network."
+ type = list(object({
+ name = string
+ description = optional(string)
+ ip_cidr_range = optional(string)
+ labels = optional(map(string), {})
+ usage = string
+ peering = string
+ prefix_length = optional(number)
+ target_cidr_range = optional(list(string))
+ exclude_cidr_ranges = optional(list(string))
+ overlaps = optional(list(string))
+ immutable = optional(bool)
+ allocation_options = optional(object({
+ allocation_strategy = optional(string)
+ first_available_ranges_lookup_size = optional(number)
+ }))
+ migration = optional(object({
+ source = string
+ target = string
+ }))
+ }))
+ default = []
+ nullable = false
+ validation {
+ condition = alltrue([
+ for r in var.internal_ranges :
+ contains(["FOR_VPC", "EXTERNAL_TO_VPC", "FOR_MIGRATION"], r.usage)
+ ])
+ error_message = "Usage must be one of: FOR_VPC, EXTERNAL_TO_VPC, FOR_MIGRATION."
+ }
+ validation {
+ condition = alltrue([
+ for r in var.internal_ranges :
+ contains(["FOR_SELF", "FOR_PEER", "NOT_SHARED"], r.peering)
+ ])
+ error_message = "Peering must be one of: FOR_SELF, FOR_PEER, NOT_SHARED."
+ }
+ validation {
+ condition = alltrue([
+ for r in var.internal_ranges : (
+ r.allocation_options == null ||
+ try(r.allocation_options.allocation_strategy, null) == null ||
+ contains(
+ ["RANDOM", "FIRST_AVAILABLE", "RANDOM_FIRST_N_AVAILABLE", "FIRST_SMALLEST_FITTING"],
+ try(r.allocation_options.allocation_strategy, "")
+ )
+ )
+ ])
+ error_message = "Allocation strategy must be one of: RANDOM, FIRST_AVAILABLE, RANDOM_FIRST_N_AVAILABLE, FIRST_SMALLEST_FITTING."
+ }
+ validation {
+ condition = alltrue([
+ for r in var.internal_ranges :
+ r.overlaps == null || alltrue([
+ for overlap in coalesce(r.overlaps, []) :
+ contains(["OVERLAP_ROUTE_RANGE", "OVERLAP_EXISTING_SUBNET_RANGE"], overlap)
+ ])
+ ])
+ error_message = "Overlaps must contain only: OVERLAP_ROUTE_RANGE, OVERLAP_EXISTING_SUBNET_RANGE."
+ }
+}
+
variable "ipv6_config" {
description = "Optional IPv6 configuration for this network."
type = object({
@@ -263,11 +328,12 @@ variable "subnets" {
description = "Subnet configuration."
type = list(object({
name = string
- ip_cidr_range = string
+ ip_cidr_range = optional(string)
region = string
description = optional(string)
enable_private_access = optional(bool, true)
allow_subnet_cidr_routes_overlap = optional(bool, null)
+ reserved_internal_range = optional(string)
flow_logs_config = optional(object({
aggregation_interval = optional(string)
filter_expression = optional(string)
@@ -282,9 +348,12 @@ variable "subnets" {
# enable_private_access = optional(string)
ipv6_only = optional(bool, false)
}))
- ip_collection = optional(string, null)
- secondary_ip_ranges = optional(map(string))
- iam = optional(map(list(string)), {})
+ ip_collection = optional(string, null)
+ secondary_ip_ranges = optional(map(object({
+ ip_cidr_range = optional(string)
+ reserved_internal_range = optional(string)
+ })))
+ iam = optional(map(list(string)), {})
iam_bindings = optional(map(object({
role = string
members = list(string)
@@ -306,6 +375,33 @@ variable "subnets" {
}))
default = []
nullable = false
+ validation {
+ condition = alltrue([
+ for s in var.subnets :
+ (
+ length([
+ for field in [s.ip_cidr_range, s.reserved_internal_range, s.ip_collection] :
+ field if field != null
+ ]) == 1
+ ) || (
+ length([
+ for field in [s.ip_cidr_range, s.reserved_internal_range, s.ip_collection] :
+ field if field != null
+ ]) == 0 && try(s.ipv6.ipv6_only, false) == true
+ )
+ ])
+ error_message = "Each subnet must specify exactly one of ip_cidr_range, reserved_internal_range, or ip_collection, or all three can be null for IPv6-only subnets (ipv6.ipv6_only = true)."
+ }
+ validation {
+ condition = alltrue([
+ for s in var.subnets :
+ s.secondary_ip_ranges == null || alltrue([
+ for range_name, range_config in coalesce(s.secondary_ip_ranges, {}) :
+ (range_config.ip_cidr_range != null) != (range_config.reserved_internal_range != null)
+ ])
+ ])
+ error_message = "Each secondary IP range must specify either ip_cidr_range or reserved_internal_range, but not both."
+ }
}
variable "subnets_private_nat" {
diff --git a/tests/fixtures/shared-vpc.tf b/tests/fixtures/shared-vpc.tf
index fcab1b9a7..2fc18972d 100644
--- a/tests/fixtures/shared-vpc.tf
+++ b/tests/fixtures/shared-vpc.tf
@@ -1,5 +1,5 @@
/**
- * Copyright 2023 Google LLC
+ * Copyright 2025 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -70,8 +70,8 @@ module "net-vpc-host" {
name = "fixture-subnet-24"
region = var.region
secondary_ip_ranges = {
- pods = "172.16.0.0/20"
- services = "192.168.0.0/24"
+ pods = { ip_cidr_range = "172.16.0.0/20" }
+ services = { ip_cidr_range = "192.168.0.0/24" }
}
},
{
@@ -79,8 +79,8 @@ module "net-vpc-host" {
name = "fixture-subnet-28"
region = var.region
secondary_ip_ranges = {
- pods = "172.16.16.0/20"
- services = "192.168.1.0/24"
+ pods = { ip_cidr_range = "172.16.16.0/20" }
+ services = { ip_cidr_range = "192.168.1.0/24" }
}
}
diff --git a/tests/modules/net_lb_app_ext/examples/serverless-neg.yaml b/tests/modules/net_lb_app_ext/examples/serverless-neg.yaml
index 0575e1ad0..fe56e41ac 100644
--- a/tests/modules/net_lb_app_ext/examples/serverless-neg.yaml
+++ b/tests/modules/net_lb_app_ext/examples/serverless-neg.yaml
@@ -1,4 +1,4 @@
-# Copyright 2023 Google LLC
+# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -62,7 +62,6 @@ values:
url_mask: null
description: Terraform managed.
name: glb-test-0-neg-0
- network: null
network_endpoint_type: SERVERLESS
project: project-id
psc_target_service: null
diff --git a/tests/modules/net_vpc/examples/internal-ranges.yaml b/tests/modules/net_vpc/examples/internal-ranges.yaml
new file mode 100644
index 000000000..98f9038bc
--- /dev/null
+++ b/tests/modules/net_vpc/examples/internal-ranges.yaml
@@ -0,0 +1,76 @@
+# Copyright 2025 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: null
+ name: my-network
+ network_firewall_policy_enforcement_order: AFTER_CLASSIC_FIREWALL
+ network_profile: null
+ params: []
+ project: project-id
+ routing_mode: GLOBAL
+ timeouts: null
+ module.vpc.google_network_connectivity_internal_range.internal_range["range1"]:
+ allocation_options: []
+ description: null
+ effective_labels:
+ goog-terraform-provisioned: 'true'
+ exclude_cidr_ranges: null
+ immutable: null
+ ip_cidr_range: 10.0.0.0/16
+ labels: null
+ migration: []
+ name: range1
+ overlaps: null
+ peering: FOR_SELF
+ prefix_length: null
+ project: project-id
+ target_cidr_range: null
+ terraform_labels:
+ goog-terraform-provisioned: 'true'
+ timeouts: null
+ usage: FOR_VPC
+ module.vpc.google_network_connectivity_internal_range.internal_range["range2"]:
+ allocation_options: []
+ description: Auto-allocated secondary range
+ effective_labels:
+ goog-terraform-provisioned: 'true'
+ exclude_cidr_ranges: null
+ immutable: null
+ labels: null
+ migration: []
+ name: range2
+ overlaps: null
+ peering: FOR_SELF
+ prefix_length: 24
+ project: project-id
+ target_cidr_range:
+ - 10.1.0.0/16
+ terraform_labels:
+ goog-terraform-provisioned: 'true'
+ timeouts: null
+ usage: FOR_VPC
+
+counts:
+ google_compute_network: 1
+ google_compute_route: 3
+ google_network_connectivity_internal_range: 2
+ modules: 1
+ resources: 6
+
+outputs: {}
diff --git a/tests/modules/net_vpc/examples/subnets-internal-ranges.yaml b/tests/modules/net_vpc/examples/subnets-internal-ranges.yaml
new file mode 100644
index 000000000..9edb090fa
--- /dev/null
+++ b/tests/modules/net_vpc/examples/subnets-internal-ranges.yaml
@@ -0,0 +1,117 @@
+# Copyright 2025 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: null
+ name: my-network
+ network_firewall_policy_enforcement_order: AFTER_CLASSIC_FIREWALL
+ network_profile: null
+ params: []
+ project: project-id
+ routing_mode: GLOBAL
+ timeouts: null
+ module.vpc.google_compute_subnetwork.subnetwork["europe-west1/production"]:
+ description: Terraform-managed.
+ ip_collection: null
+ ipv6_access_type: null
+ log_config: []
+ name: production
+ network: my-network
+ params: []
+ private_ip_google_access: true
+ project: project-id
+ region: europe-west1
+ role: null
+ secondary_ip_range:
+ - range_name: pods
+ - range_name: services
+ - ip_cidr_range: 192.168.0.0/24
+ range_name: traditional
+ reserved_internal_range: null
+ send_secondary_ip_range_if_empty: true
+ timeouts: null
+ module.vpc.google_network_connectivity_internal_range.internal_range["pods-range"]:
+ allocation_options: []
+ description: null
+ effective_labels:
+ goog-terraform-provisioned: 'true'
+ exclude_cidr_ranges: null
+ immutable: null
+ ip_cidr_range: 10.1.0.0/16
+ labels: null
+ migration: []
+ name: pods-range
+ overlaps: null
+ peering: FOR_SELF
+ prefix_length: null
+ project: project-id
+ target_cidr_range: null
+ terraform_labels:
+ goog-terraform-provisioned: 'true'
+ timeouts: null
+ usage: FOR_VPC
+ module.vpc.google_network_connectivity_internal_range.internal_range["services-range"]:
+ allocation_options: []
+ description: null
+ effective_labels:
+ goog-terraform-provisioned: 'true'
+ exclude_cidr_ranges: null
+ immutable: null
+ labels: null
+ migration: []
+ name: services-range
+ overlaps: null
+ peering: FOR_SELF
+ prefix_length: 20
+ project: project-id
+ target_cidr_range:
+ - 10.2.0.0/16
+ terraform_labels:
+ goog-terraform-provisioned: 'true'
+ timeouts: null
+ usage: FOR_VPC
+ module.vpc.google_network_connectivity_internal_range.internal_range["subnet-range"]:
+ allocation_options: []
+ description: null
+ effective_labels:
+ goog-terraform-provisioned: 'true'
+ exclude_cidr_ranges: null
+ immutable: null
+ ip_cidr_range: 10.0.1.0/24
+ labels: null
+ migration: []
+ name: subnet-range
+ overlaps: null
+ peering: FOR_SELF
+ prefix_length: null
+ project: project-id
+ target_cidr_range: null
+ terraform_labels:
+ goog-terraform-provisioned: 'true'
+ timeouts: null
+ usage: FOR_VPC
+
+counts:
+ google_compute_network: 1
+ google_compute_route: 3
+ google_compute_subnetwork: 1
+ google_network_connectivity_internal_range: 3
+ modules: 1
+ resources: 8
+
+outputs: {}