Add support for IPv6 only subnets and IP collections

This commit is contained in:
Chris McCoy
2025-06-16 22:06:47 -04:00
committed by Wiktor Niesiobędzki
parent ad0910b7b6
commit c33a4b57c1
6 changed files with 164 additions and 13 deletions

View File

@@ -23,6 +23,7 @@ This module allows creation and management of VPC networks including subnetworks
- [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)
- [IPv6-Only and IP Collections](#ipv6-only-and-ip-collections)
- [Variables](#variables)
- [Outputs](#outputs)
<!-- END TOC -->
@@ -712,6 +713,47 @@ module "vpc" {
}
# tftest modules=1 resources=6 inventory=ipv6.yaml e2e
```
### 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.
```hcl
module "vpc" {
source = "./fabric/modules/net-vpc"
project_id = var.project_id
name = "my-network"
ipv6_config = {
enable_ula_internal = true
}
subnets = [
{
ip_cidr_range = null
name = "test-v6only"
region = "europe-west1"
ipv6 = {
ipv6_only = true
}
},
{
ip_cidr_range = null
name = "test-v6only"
region = "europe-west3"
ipv6 = {
access_type = "EXTERNAL"
ipv6_only = true
}
ip_collection = "https://www.googleapis.com/compute/v1/projects/project-id/regions/europe-west3/publicDelegatedPrefixes/test-sub-pdp"
}
]
}
# tftest modules=1 resources=6 inventory=ipv6_only.yaml e2e
```
<!-- BEGIN TFDOC -->
## Variables
@@ -736,11 +778,11 @@ module "vpc" {
| [routing_mode](variables.tf#L234) | The network routing mode (default 'GLOBAL'). | <code>string</code> | | <code>&#34;GLOBAL&#34;</code> |
| [shared_vpc_host](variables.tf#L244) | Enable shared VPC for this project. | <code>bool</code> | | <code>false</code> |
| [shared_vpc_service_projects](variables.tf#L250) | Shared VPC service projects to register with this host. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> |
| [subnets](variables.tf#L256) | Subnet configuration. | <code title="list&#40;object&#40;&#123;&#10; name &#61; string&#10; ip_cidr_range &#61; string&#10; region &#61; string&#10; description &#61; optional&#40;string&#41;&#10; enable_private_access &#61; optional&#40;bool, true&#41;&#10; allow_subnet_cidr_routes_overlap &#61; optional&#40;bool, null&#41;&#10; flow_logs_config &#61; optional&#40;object&#40;&#123;&#10; aggregation_interval &#61; optional&#40;string&#41;&#10; filter_expression &#61; optional&#40;string&#41;&#10; flow_sampling &#61; optional&#40;number&#41;&#10; metadata &#61; optional&#40;string&#41;&#10; metadata_fields &#61; optional&#40;list&#40;string&#41;&#41;&#10; &#125;&#41;&#41;&#10; ipv6 &#61; optional&#40;object&#40;&#123;&#10; access_type &#61; optional&#40;string, &#34;INTERNAL&#34;&#41;&#10; &#125;&#41;&#41;&#10; secondary_ip_ranges &#61; optional&#40;map&#40;string&#41;&#41;&#10; iam &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; iam_bindings &#61; optional&#40;map&#40;object&#40;&#123;&#10; role &#61; string&#10; members &#61; list&#40;string&#41;&#10; condition &#61; optional&#40;object&#40;&#123;&#10; expression &#61; string&#10; title &#61; string&#10; description &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;, &#123;&#125;&#41;&#10; iam_bindings_additive &#61; optional&#40;map&#40;object&#40;&#123;&#10; member &#61; string&#10; role &#61; string&#10; condition &#61; optional&#40;object&#40;&#123;&#10; expression &#61; string&#10; title &#61; string&#10; description &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;, &#123;&#125;&#41;&#10;&#125;&#41;&#41;">list&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#91;&#93;</code> |
| [subnets_private_nat](variables.tf#L303) | List of private NAT subnets. | <code title="list&#40;object&#40;&#123;&#10; name &#61; string&#10; ip_cidr_range &#61; string&#10; region &#61; string&#10; description &#61; optional&#40;string&#41;&#10;&#125;&#41;&#41;">list&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#91;&#93;</code> |
| [subnets_proxy_only](variables.tf#L315) | 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. | <code title="list&#40;object&#40;&#123;&#10; name &#61; string&#10; ip_cidr_range &#61; string&#10; region &#61; string&#10; description &#61; optional&#40;string&#41;&#10; active &#61; optional&#40;bool, true&#41;&#10; global &#61; optional&#40;bool, false&#41;&#10;&#10;&#10; iam &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; iam_bindings &#61; optional&#40;map&#40;object&#40;&#123;&#10; role &#61; string&#10; members &#61; list&#40;string&#41;&#10; condition &#61; optional&#40;object&#40;&#123;&#10; expression &#61; string&#10; title &#61; string&#10; description &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;, &#123;&#125;&#41;&#10; iam_bindings_additive &#61; optional&#40;map&#40;object&#40;&#123;&#10; member &#61; string&#10; role &#61; string&#10; condition &#61; optional&#40;object&#40;&#123;&#10; expression &#61; string&#10; title &#61; string&#10; description &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;, &#123;&#125;&#41;&#10;&#125;&#41;&#41;">list&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#91;&#93;</code> |
| [subnets_psc](variables.tf#L349) | List of subnets for Private Service Connect service producers. | <code title="list&#40;object&#40;&#123;&#10; name &#61; string&#10; ip_cidr_range &#61; string&#10; region &#61; string&#10; description &#61; optional&#40;string&#41;&#10;&#10;&#10; iam &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; iam_bindings &#61; optional&#40;map&#40;object&#40;&#123;&#10; role &#61; string&#10; members &#61; list&#40;string&#41;&#10; condition &#61; optional&#40;object&#40;&#123;&#10; expression &#61; string&#10; title &#61; string&#10; description &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;, &#123;&#125;&#41;&#10; iam_bindings_additive &#61; optional&#40;map&#40;object&#40;&#123;&#10; member &#61; string&#10; role &#61; string&#10; condition &#61; optional&#40;object&#40;&#123;&#10; expression &#61; string&#10; title &#61; string&#10; description &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;, &#123;&#125;&#41;&#10;&#125;&#41;&#41;">list&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#91;&#93;</code> |
| [vpc_create](variables.tf#L381) | Create VPC. When set to false, uses a data source to reference existing VPC. | <code>bool</code> | | <code>true</code> |
| [subnets](variables.tf#L256) | Subnet configuration. | <code title="list&#40;object&#40;&#123;&#10; name &#61; string&#10; ip_cidr_range &#61; string&#10; region &#61; string&#10; description &#61; optional&#40;string&#41;&#10; enable_private_access &#61; optional&#40;bool, true&#41;&#10; allow_subnet_cidr_routes_overlap &#61; optional&#40;bool, null&#41;&#10; flow_logs_config &#61; optional&#40;object&#40;&#123;&#10; aggregation_interval &#61; optional&#40;string&#41;&#10; filter_expression &#61; optional&#40;string&#41;&#10; flow_sampling &#61; optional&#40;number&#41;&#10; metadata &#61; optional&#40;string&#41;&#10; metadata_fields &#61; optional&#40;list&#40;string&#41;&#41;&#10; &#125;&#41;&#41;&#10; ipv6 &#61; optional&#40;object&#40;&#123;&#10; access_type &#61; optional&#40;string, &#34;INTERNAL&#34;&#41;&#10; ipv6_only &#61; optional&#40;bool, false&#41;&#10; &#125;&#41;&#41;&#10; ip_collection &#61; optional&#40;string, null&#41;&#10; secondary_ip_ranges &#61; optional&#40;map&#40;string&#41;&#41;&#10; iam &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; iam_bindings &#61; optional&#40;map&#40;object&#40;&#123;&#10; role &#61; string&#10; members &#61; list&#40;string&#41;&#10; condition &#61; optional&#40;object&#40;&#123;&#10; expression &#61; string&#10; title &#61; string&#10; description &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;, &#123;&#125;&#41;&#10; iam_bindings_additive &#61; optional&#40;map&#40;object&#40;&#123;&#10; member &#61; string&#10; role &#61; string&#10; condition &#61; optional&#40;object&#40;&#123;&#10; expression &#61; string&#10; title &#61; string&#10; description &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;, &#123;&#125;&#41;&#10;&#125;&#41;&#41;">list&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#91;&#93;</code> |
| [subnets_private_nat](variables.tf#L305) | List of private NAT subnets. | <code title="list&#40;object&#40;&#123;&#10; name &#61; string&#10; ip_cidr_range &#61; string&#10; region &#61; string&#10; description &#61; optional&#40;string&#41;&#10;&#125;&#41;&#41;">list&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#91;&#93;</code> |
| [subnets_proxy_only](variables.tf#L317) | 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. | <code title="list&#40;object&#40;&#123;&#10; name &#61; string&#10; ip_cidr_range &#61; string&#10; region &#61; string&#10; description &#61; optional&#40;string&#41;&#10; active &#61; optional&#40;bool, true&#41;&#10; global &#61; optional&#40;bool, false&#41;&#10;&#10;&#10; iam &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; iam_bindings &#61; optional&#40;map&#40;object&#40;&#123;&#10; role &#61; string&#10; members &#61; list&#40;string&#41;&#10; condition &#61; optional&#40;object&#40;&#123;&#10; expression &#61; string&#10; title &#61; string&#10; description &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;, &#123;&#125;&#41;&#10; iam_bindings_additive &#61; optional&#40;map&#40;object&#40;&#123;&#10; member &#61; string&#10; role &#61; string&#10; condition &#61; optional&#40;object&#40;&#123;&#10; expression &#61; string&#10; title &#61; string&#10; description &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;, &#123;&#125;&#41;&#10;&#125;&#41;&#41;">list&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#91;&#93;</code> |
| [subnets_psc](variables.tf#L351) | List of subnets for Private Service Connect service producers. | <code title="list&#40;object&#40;&#123;&#10; name &#61; string&#10; ip_cidr_range &#61; string&#10; region &#61; string&#10; description &#61; optional&#40;string&#41;&#10;&#10;&#10; iam &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; iam_bindings &#61; optional&#40;map&#40;object&#40;&#123;&#10; role &#61; string&#10; members &#61; list&#40;string&#41;&#10; condition &#61; optional&#40;object&#40;&#123;&#10; expression &#61; string&#10; title &#61; string&#10; description &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;, &#123;&#125;&#41;&#10; iam_bindings_additive &#61; optional&#40;map&#40;object&#40;&#123;&#10; member &#61; string&#10; role &#61; string&#10; condition &#61; optional&#40;object&#40;&#123;&#10; expression &#61; string&#10; title &#61; string&#10; description &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;, &#123;&#125;&#41;&#10;&#125;&#41;&#41;">list&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#91;&#93;</code> |
| [vpc_create](variables.tf#L383) | Create VPC. When set to false, uses a data source to reference existing VPC. | <code>bool</code> | | <code>true</code> |
## Outputs

View File

@@ -56,9 +56,15 @@
"properties": {
"access_type": {
"type": "string"
},
"ipv6_only": {
"type": "boolean"
}
}
},
"ip_collection": {
"type": "string"
},
"name": {
"type": "string"
},

View File

@@ -23,6 +23,8 @@
- **ipv6**: *object*
<br>*additional properties: false*
- **access_type**: *string*
- +**ipv6_only**: *boolean*
- ⁺**ip_collection**: *string*
- **name**: *string*
- ⁺**region**: *string*
- **psc**: *boolean*

View File

@@ -43,7 +43,9 @@ locals {
ip_cidr_range = v.ip_cidr_range
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)
@@ -139,13 +141,21 @@ locals {
}
resource "google_compute_subnetwork" "subnetwork" {
provider = google-beta
for_each = local.subnets
project = var.project_id
network = local.network.name
name = each.value.name
region = each.value.region
ip_cidr_range = each.value.ip_cidr_range
provider = google-beta
for_each = local.subnets
project = var.project_id
network = local.network.name
name = each.value.name
region = each.value.region
ip_cidr_range = (
try(each.value.ipv6, null) != null
? (
try(each.value.ipv6.ipv6_only, false)
? null
: each.value.ip_cidr_range
)
: each.value.ip_cidr_range
)
allow_subnet_cidr_routes_overlap = each.value.allow_subnet_cidr_routes_overlap
description = (
each.value.description == null
@@ -154,12 +164,19 @@ resource "google_compute_subnetwork" "subnetwork" {
)
private_ip_google_access = each.value.enable_private_access
stack_type = (
try(each.value.ipv6, null) != null ? "IPV4_IPV6" : null
try(each.value.ipv6, null) != null
? (
try(each.value.ipv6.ipv6_only, false)
? "IPV6_ONLY"
: "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)
ip_collection = each.value.ip_collection
send_secondary_ip_range_if_empty = true
dynamic "secondary_ip_range" {

View File

@@ -274,7 +274,9 @@ variable "subnets" {
access_type = optional(string, "INTERNAL")
# this field is marked for internal use in the API documentation
# 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)), {})
iam_bindings = optional(map(object({