Module: net-vpc-factory (#2982)

This pull request introduces the `net-vpc-factory` module. This new factory handles: 

* Project setup (most of what's supported by the `project` module)
* VPC setup
  * Routing
  * Subnets
* Connectivity options
  * NCC (hub, VPC spokes and VPN hybrid spokes)
  * Peerings
  * VPN (GCP-to-onprem and GCP-to-GCP)
* NAT (everything supported by the `net-cloudnat` module)
* DNS (everything supported by the `dns` module)
* Firewall (everything supported by the `net-vpc-firewall` module)
This commit is contained in:
Simone Ruffilli
2025-04-10 11:44:39 +02:00
committed by GitHub
parent f7a0958e17
commit fc84c4f60d
48 changed files with 4728 additions and 1 deletions

View File

@@ -31,7 +31,7 @@ Currently available modules:
- **foundational** - [billing account](./modules/billing-account), [Cloud Identity group](./modules/cloud-identity-group/), [folder](./modules/folder), [service accounts](./modules/iam-service-account), [logging bucket](./modules/logging-bucket), [organization](./modules/organization), [project](./modules/project), [projects-data-source](./modules/projects-data-source)
- **process factories** - [project factory](./modules/project-factory/README.md)
- **networking** - [DNS](./modules/dns), [DNS Response Policy](./modules/dns-response-policy/), [Cloud Endpoints](./modules/endpoints), [address reservation](./modules/net-address), [NAT](./modules/net-cloudnat), [VLAN Attachment](./modules/net-vlan-attachment/), [External Application LB](./modules/net-lb-app-ext/), [External Passthrough Network LB](./modules/net-lb-ext), [External Regional Application Load Balancer](./modules/net-lb-app-ext-regional/), [Firewall policy](./modules/net-firewall-policy), [Internal Application LB](./modules/net-lb-app-int), [Cross-region Internal Application LB](./modules/net-lb-app-int-cross-region), [Internal Passthrough Network LB](./modules/net-lb-int), [Internal Proxy Network LB](./modules/net-lb-proxy-int), [IPSec over Interconnect](./modules/net-ipsec-over-interconnect), [VPC](./modules/net-vpc), [VPC firewall](./modules/net-vpc-firewall), [VPC peering](./modules/net-vpc-peering), [VPN dynamic](./modules/net-vpn-dynamic), [HA VPN](./modules/net-vpn-ha), [VPN static](./modules/net-vpn-static), [Service Directory](./modules/service-directory), [Secure Web Proxy](./modules/net-swp)
- **networking** - [DNS](./modules/dns), [DNS Response Policy](./modules/dns-response-policy/), [Cloud Endpoints](./modules/endpoints), [address reservation](./modules/net-address), [NAT](./modules/net-cloudnat), [VLAN Attachment](./modules/net-vlan-attachment/), [External Application LB](./modules/net-lb-app-ext/), [External Passthrough Network LB](./modules/net-lb-ext), [External Regional Application Load Balancer](./modules/net-lb-app-ext-regional/), [Firewall policy](./modules/net-firewall-policy), [Internal Application LB](./modules/net-lb-app-int), [Cross-region Internal Application LB](./modules/net-lb-app-int-cross-region), [Internal Passthrough Network LB](./modules/net-lb-int), [Internal Proxy Network LB](./modules/net-lb-proxy-int), [IPSec over Interconnect](./modules/net-ipsec-over-interconnect), [VPC](./modules/net-vpc), [VPC factory](./modules/net-vpc-factory/README.md), [VPC firewall](./modules/net-vpc-firewall), [VPC peering](./modules/net-vpc-peering), [VPN dynamic](./modules/net-vpn-dynamic), [HA VPN](./modules/net-vpn-ha), [VPN static](./modules/net-vpn-static), [Service Directory](./modules/service-directory), [Secure Web Proxy](./modules/net-swp)
- **compute** - [VM/VM group](./modules/compute-vm), [MIG](./modules/compute-mig), [COS container](./modules/cloud-config-container/cos-generic-metadata/) (coredns, mysql, onprem, squid), [GKE cluster](./modules/gke-cluster-standard), [GKE hub](./modules/gke-hub), [GKE nodepool](./modules/gke-nodepool), [GCVE private cloud](./modules/gcve-private-cloud)
- **data** - [AlloyDB instance](./modules/alloydb), [Analytics Hub](./modules/analytics-hub), [BigQuery dataset](./modules/bigquery-dataset), [Biglake Catalog](./modules/biglake-catalog), [Bigtable instance](./modules/bigtable-instance), [Dataplex](./modules/dataplex), [Dataplex DataScan](./modules/dataplex-datascan), [Cloud SQL instance](./modules/cloudsql-instance), [Spanner instance](./modules/spanner-instance), [Firestore](./modules/firestore), [Data Catalog Policy Tag](./modules/data-catalog-policy-tag), [Data Catalog Tag](./modules/data-catalog-tag), [Data Catalog Tag Template](./modules/data-catalog-tag-template), [Datafusion](./modules/datafusion), [Dataproc](./modules/dataproc), [GCS](./modules/gcs), [Pub/Sub](./modules/pubsub), [Dataform Repository](./modules/dataform-repository/), [Looker Core](./modules/looker-core)
- **development** - [API Gateway](./modules/api-gateway), [Apigee](./modules/apigee), [Artifact Registry](./modules/artifact-registry), [Container Registry](./modules/container-registry), [Cloud Source Repository](./modules/source-repository), [Secure Source Manager instance](./modules/secure-source-manager-instance), [Workstation cluster](./modules/workstation-cluster)

View File

@@ -74,3 +74,5 @@ The second factory type is implemented as a standalone module that internally re
- **projects**
- [`project-factory`](../../modules/project-factory/)
- **VPCs**
- [`net-vpc-factory`](../../modules/net-vpc-factory/)

View File

@@ -60,6 +60,7 @@ These modules are used in the examples included in this repository. If you are u
- [NAT](./net-cloudnat)
- [Service Directory](./service-directory)
- [VPC](./net-vpc)
- [VPC factory](./net-vpc-factory)
- [VPC firewall](./net-vpc-firewall)
- [VPN dynamic](./net-vpn-dynamic)
- [VPC peering](./net-vpc-peering)

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,28 @@
# skip boilerplate check
---
# start of document (---) avoids errors if the file only contains comments
# yaml-language-server: $schema=../../../schemas/firewall-rules.schema.json
ingress:
ingress-icmp-allow:
description: "Allow ICMP from anywhere."
rules:
- protocol: icmp
ports: []
priority: 1000
ingress-ssh-from-iap-allow:
description: "Allow SSH connections from IAP ranges."
source_ranges:
- 35.235.240.0/20
rules:
- protocol: tcp
ports:
- 22
priority: 1001
ingress-default-deny:
description: "Deny and log any unmatched ingress traffic."
deny: true
priority: 65535
enable_logging:
include_metadata: false

View File

@@ -0,0 +1,28 @@
# skip boilerplate check
---
# start of document (---) avoids errors if the file only contains comments
# yaml-language-server: $schema=../../../schemas/firewall-rules.schema.json
ingress:
ingress-icmp-allow:
description: "Allow ICMP from anywhere."
rules:
- protocol: icmp
ports: []
priority: 1000
ingress-ssh-from-iap-allow:
description: "Allow SSH connections from IAP ranges."
source_ranges:
- 35.235.240.0/20
rules:
- protocol: tcp
ports:
- 22
priority: 1001
ingress-default-deny:
description: "Deny and log any unmatched ingress traffic."
deny: true
priority: 65535
enable_logging:
include_metadata: false

View File

@@ -0,0 +1,28 @@
# skip boilerplate check
---
# start of document (---) avoids errors if the file only contains comments
# yaml-language-server: $schema=../../../schemas/firewall-rules.schema.json
ingress:
ingress-icmp-allow:
description: "Allow ICMP from anywhere."
rules:
- protocol: icmp
ports: []
priority: 1000
ingress-ssh-from-iap-allow:
description: "Allow SSH connections from IAP ranges."
source_ranges:
- 35.235.240.0/20
rules:
- protocol: tcp
ports:
- 22
priority: 1001
ingress-default-deny:
description: "Deny and log any unmatched ingress traffic."
deny: true
priority: 65535
enable_logging:
include_metadata: false

View File

@@ -0,0 +1,8 @@
# skip boilerplate check
# yaml-language-server: $schema=../../../schemas/subnet.schema.json
name: dev-default
region: europe-west8
ip_cidr_range: 10.68.0.0/24
description: Default europe-west8 subnet for dev

View File

@@ -0,0 +1,8 @@
# skip boilerplate check
# yaml-language-server: $schema=../../../schemas/subnet.schema.json
name: hub-default
region: europe-west12
ip_cidr_range: 10.70.0.0/24
description: Default europe-west12 subnet for hub

View File

@@ -0,0 +1,8 @@
# skip boilerplate check
# yaml-language-server: $schema=../../../schemas/subnet.schema.json
name: prod-default
region: europe-west12
ip_cidr_range: 10.69.0.0/24
description: Default europe-west12 subnet for prod

View File

@@ -0,0 +1,87 @@
/**
* 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.
*/
# tfdoc:file:description DNS factory.
locals {
dns_zone_entries = flatten([
for factory_key, factory_config in local.network_projects : [
for vpc_key, vpc_config in try(factory_config.vpc_config, {}) : [
for zone_key, zone in try(vpc_config.dns_zones, {}) : {
key = "${factory_key}/${vpc_key}/${zone_key}"
value = merge(
{
name = replace("${vpc_key}-${zone_key}", "/", "-")
project_id = module.projects[factory_key].id
description = try(zone.description, "Terraform-managed.")
force_destroy = try(zone.force_destroy, null)
iam = try(zone.iam, null)
recordsets = try(zone.recordsets, null)
},
{
zone_config = merge(
{ domain = try(zone.zone_config.domain, null) },
contains(keys(try(zone.zone_config, {})), "private") ? {
private = {
service_directory_namespace = try(zone.zone_config.private.service_directory_namespace, null)
client_networks = [
for net in zone.zone_config.private.client_networks :
try(module.vpc[net].self_link, net)
]
}
} : {},
contains(keys(try(zone.zone_config, {})), "peering") ? {
peering = {
peer_network = try(module.vpc[zone.zone_config.peering.peer_network].self_link, zone.zone_config.peering.peer_network),
client_networks = [
for net in zone.zone_config.peering.client_networks :
try(module.vpc[net].self_link, net)
]
}
} : {},
contains(keys(try(zone.zone_config, {})), "forwarding") ? {
forwarding = {
forwarders = try(zone.zone_config.forwarding.forwarders, {}),
client_networks = [
for net in zone.zone_config.forwarding.client_networks :
try(module.vpc[net].self_link, net)
]
}
} : {}
)
}
)
}
]
]
])
# Convert the flattened list into a map.
dns_zones = { for entry in local.dns_zone_entries : entry.key => entry.value }
}
module "dns-zones" {
source = "../dns"
for_each = local.dns_zones
project_id = each.value.project_id
name = each.value.name
description = each.value.description
force_destroy = each.value.force_destroy
iam = each.value.iam
zone_config = each.value.zone_config
recordsets = each.value.recordsets
depends_on = [module.vpc]
}

View File

@@ -0,0 +1,62 @@
/**
* 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.
*/
# tfdoc:file:description Cloud NAT factory.
locals {
nat_configs = merge(flatten([
for factory_key, factory_config in local.network_projects : [
for vpc_key, vpc_config in try(factory_config.vpc_config, {}) : [
for nat_key, nat_config in try(vpc_config.nat_config, {}) : {
"${factory_key}/${vpc_key}/${nat_key}" = merge(nat_config, {
name = replace("${vpc_key}/${nat_key}", "/", "-")
project_id = module.projects[factory_key].id
addresses = try(nat_config.addresses, [])
config_port_allocation = try(nat_config.config_port_allocation, {})
config_source_subnetworks = try(nat_config.config_source_subnetworks, {})
config_timeouts = try(nat_config.config_timeouts, {})
endpoint_types = try(nat_config.endpoint_types, null)
logging_filter = try(nat_config.logging_filter, null)
router_asn = try(nat_config.router_asn, null)
router_create = try(nat_config.router_create, true)
router_network = module.vpc["${factory_key}/${vpc_key}"].self_link
rules = try(nat_config.rules, [])
type = try(nat_config.type, "PUBLIC")
})
}
]
]
])...)
}
module "nat" {
source = "../net-cloudnat"
for_each = local.nat_configs
project_id = each.value.project_id
name = each.value.name
addresses = each.value.addresses
config_port_allocation = each.value.config_port_allocation
config_source_subnetworks = each.value.config_source_subnetworks
config_timeouts = each.value.config_timeouts
endpoint_types = each.value.endpoint_types
logging_filter = each.value.logging_filter
region = each.value.region
router_asn = each.value.router_asn
router_create = each.value.router_create
router_network = each.value.router_network
rules = each.value.rules
type = each.value.type
}

View File

@@ -0,0 +1,139 @@
/**
* 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.
*/
# tfdoc:file:description NCC factory.
locals {
ncc_hubs = { for k, v in local.network_projects : "${k}/${v.ncc_hub_config.name}" =>
{
name = v.ncc_hub_config.name
project_id = module.projects[k].id
description = try(v.ncc_hub_config.description, "Terraform-managed")
export_psc = try(v.ncc_hub_config.export_psc, true)
preset_topology = try(v.ncc_hub_config.preset_topology, "MESH")
}
if try(v.ncc_hub_config != null, false)
}
ncc_groups = merge(flatten([for k, v in local.network_projects :
{
for gk, gv in try(v.ncc_hub_config.groups, {}) : "${k}/${v.ncc_hub_config.name}/${gk}" =>
{
name = gk
project = module.projects[k].id
hub = google_network_connectivity_hub.default["${k}/${v.ncc_hub_config.name}"].id
description = try(gv.description, "Terraform-managed")
labels = try(gv.labels, {})
auto_accept = [for project_key in try(gv.auto_accept, []) : module.projects[project_key].id]
}
}
if try(v.ncc_hub_config != null, false)
])...)
ncc_vpn_spokes = merge(flatten([
for factory_key, factory_config in local.network_projects : [
for vpc_key, vpc_config in try(factory_config.vpc_config, {}) : [
for vpn_key, vpn_config in try(vpc_config.vpn_config, {}) : {
"${factory_key}/${vpc_key}/${vpn_key}" = {
name = replace("${factory_key}/${vpc_key}/${vpn_key}", "/", "-")
project_id = module.projects[factory_key].id
hub = google_network_connectivity_hub.default[vpn_config.ncc_spoke_config.hub].id
location = vpn_config.region
description = lookup(vpn_config.ncc_spoke_config, "description", "Terraform-managed.")
labels = lookup(vpn_config.ncc_spoke_config, "labels", {})
tunnel_self_link = [for t, _ in vpn_config.tunnels : module.vpn-ha["${factory_key}/${vpc_key}/${vpn_key}"].tunnel_self_links[t]]
}
}
if try(vpn_config.ncc_spoke_config != null, false)
]
]
])...)
ncc_vpc_spokes = merge(flatten([
for factory_key, factory_config in local.network_projects : {
for vpc_key, vpc_config in try(factory_config.vpc_config, {}) : "${factory_key}/${vpc_key}" => merge(vpc_config.ncc_config, {
project_id = module.projects[factory_key].id
network_self_link = module.vpc["${factory_key}/${vpc_key}"].self_link
labels = try(vpc_config.ncc_config.labels, {})
hub = google_network_connectivity_hub.default[vpc_config.ncc_config.hub].id
description = try(vpc_config.ncc_config.description, "Terraform-managed")
exclude_export_ranges = try(vpc_config.ncc_config.exclude_export_ranges, null)
include_export_ranges = try(vpc_config.ncc_config.include_export_ranges, null)
group = try(google_network_connectivity_group.default[vpc_config.ncc_config.group].id, null)
})
if try(vpc_config.ncc_config != null, false)
}
])...)
}
resource "google_network_connectivity_hub" "default" {
for_each = local.ncc_hubs
name = each.value.name
description = each.value.description
export_psc = each.value.export_psc
preset_topology = each.value.preset_topology
project = each.value.project_id
}
resource "google_network_connectivity_spoke" "vpcs" {
for_each = local.ncc_vpc_spokes
project = each.value.project_id
name = replace(each.key, "/", "-")
location = "global"
description = each.value.description
labels = each.value.labels
hub = each.value.hub
linked_vpc_network {
uri = each.value.network_self_link
exclude_export_ranges = each.value.exclude_export_ranges
include_export_ranges = each.value.include_export_ranges
}
depends_on = [google_network_connectivity_hub.default]
group = each.value.group
}
resource "google_network_connectivity_group" "default" {
for_each = local.ncc_groups
project = each.value.project
name = each.value.name
hub = each.value.hub
labels = each.value.labels
description = each.value.description
dynamic "auto_accept" {
for_each = try(each.value.auto_accept != null, false) ? [""] : []
content {
auto_accept_projects = each.value.auto_accept
}
}
depends_on = [google_network_connectivity_hub.default]
}
resource "google_network_connectivity_spoke" "tunnels" {
for_each = local.ncc_vpn_spokes
project = each.value.project_id
name = each.value.name
location = each.value.location
description = each.value.description
labels = each.value.labels
hub = each.value.hub
linked_vpn_tunnels {
uris = each.value.tunnel_self_link
site_to_site_data_transfer = true
include_import_ranges = ["ALL_IPV4_RANGES"]
}
depends_on = [module.vpn-ha]
}

View File

@@ -0,0 +1,51 @@
/**
* 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.
*/
# tfdoc:file:description Peering factory.
locals {
peerings = merge(flatten([
for factory_key, factory_config in local.network_projects : [
for vpc_key, vpc_config in try(factory_config.vpc_config, {}) : [
for k, v in try(vpc_config.peering_config, {}) : {
"${factory_key}/${vpc_key}/${k}" = {
project = factory_key
name = replace("${vpc_key}/${k}", "/", "-")
local_network = module.vpc["${factory_key}/${vpc_key}"].self_link
peer_network = module.vpc[v.peer_network].self_link
export_custom_routes = try(v.routes_config.export, true)
import_custom_routes = try(v.routes_config.import, true)
export_subnet_routes_with_public_ip = try(v.routes_config.public_export, null)
import_subnet_routes_with_public_ip = try(v.routes_config.public_import, null)
stack_type = try(v.stack_type, null)
}
}
]
]
])...)
}
resource "google_compute_network_peering" "default" {
for_each = local.peerings
name = each.value.name
network = each.value.local_network
peer_network = each.value.peer_network
export_custom_routes = each.value.export_custom_routes
import_custom_routes = each.value.import_custom_routes
export_subnet_routes_with_public_ip = each.value.export_subnet_routes_with_public_ip
import_subnet_routes_with_public_ip = each.value.import_subnet_routes_with_public_ip
stack_type = each.value.stack_type
}

View File

@@ -0,0 +1,53 @@
/**
* 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.
*/
# tfdoc:file:description Dedicated project factory.
locals {
projects = { for k, v in local.network_projects : k => merge(
{
billing_account = try(v.project_config.billing_account, var.billing_account)
prefix = try(v.project_config.prefix, var.prefix)
parent = try(v.project_config.parent, var.parent_id)
shared_vpc_host_config = try(v.project_config.shared_vpc_host_config, null)
iam = try(v.project_config.iam, {})
iam_bindings = try(v.project_config.iam_bindings, {})
iam_bindings_additive = try(v.project_config.iam_bindings_additive, {})
iam_by_principals = try(v.project_config.iam_by_principals, {})
iam_by_principals_additive = try(v.project_config.iam_by_principals_additive, {})
services = try(v.project_config.services, [])
org_policies = try(v.project_config.org_policies, {})
},
v.project_config)
}
}
module "projects" {
source = "../project"
for_each = local.projects
billing_account = each.value.billing_account
name = each.value.name
parent = each.value.parent
prefix = each.value.prefix
services = each.value.services
shared_vpc_host_config = each.value.shared_vpc_host_config
iam = each.value.iam
iam_bindings = each.value.iam_bindings
iam_bindings_additive = each.value.iam_bindings_additive
iam_by_principals = each.value.iam_by_principals
iam_by_principals_additive = each.value.iam_by_principals_additive
org_policies = each.value.org_policies
}

View File

@@ -0,0 +1,80 @@
/**
* 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.
*/
# tfdoc:file:description VPC and firewall factory.
locals {
_vpcs_preprocess = [for factory_key, factory_config in local.network_projects : {
for k, v in try(factory_config.vpc_config, {}) : "${factory_key}/${k}" => {
project_id = module.projects[factory_key].id
name = k
auto_create_subnetworks = try(v.auto_create_subnetworks, false)
create_googleapis_routes = try(v.create_googleapis_routes, {})
delete_default_routes_on_create = try(v.delete_default_routes_on_create, false)
description = try(v.description, "Terraform-managed.")
dns_policy = try(v.dns_policy, {})
firewall_policy_enforcement_order = try(v.firewall_policy_enforcement_order, "AFTER_CLASSIC_FIREWALL")
ipv6_config = try(v.ipv6_config, {})
mtu = try(v.mtu, null)
network_attachments = try(v.network_attachments, {})
policy_based_routes = try(v.policy_based_routes, {})
psa_config = try(v.psa_config, [])
routes = try(v.routes, {})
routing_mode = try(v.routing_mode, "GLOBAL")
subnets_factory_config = try(v.subnets_factory_config, {})
firewall_factory_config = try(v.firewall_factory_config, {})
peering_config = try(v.peering_config, {})
vpn_config = try(v.vpn_config, {})
}
}]
vpcs = merge(
merge(local._vpcs_preprocess...),
var.network_project_config
)
}
module "vpc" {
source = "../net-vpc"
for_each = local.vpcs
project_id = each.value.project_id
name = each.value.name
description = each.value.description
auto_create_subnetworks = each.value.auto_create_subnetworks
create_googleapis_routes = each.value.create_googleapis_routes
delete_default_routes_on_create = each.value.delete_default_routes_on_create
dns_policy = each.value.dns_policy
factories_config = each.value.subnets_factory_config
firewall_policy_enforcement_order = each.value.firewall_policy_enforcement_order
ipv6_config = each.value.ipv6_config
mtu = each.value.mtu
network_attachments = each.value.network_attachments
policy_based_routes = each.value.policy_based_routes
psa_configs = each.value.psa_config
routes = each.value.routes
routing_mode = each.value.routing_mode
depends_on = [module.projects]
}
module "firewall" {
source = "../net-vpc-firewall"
for_each = { for k, v in local.vpcs : k => v if v.firewall_factory_config != null }
project_id = each.value.project_id
network = each.value.name
factories_config = each.value.firewall_factory_config
default_rules_config = { disabled = true }
depends_on = [module.vpc]
}

View File

@@ -0,0 +1,111 @@
/**
* 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.
*/
# tfdoc:file:description VPN factory.
locals {
routers = merge(flatten([
for factory_key, factory_config in local.network_projects : [
for vpc_key, vpc_config in try(factory_config.vpc_config, {}) : [
for router_key, router_config in try(vpc_config.routers, {}) : {
"${factory_key}/${vpc_key}/${router_key}" = merge(router_config, {
vpc_self_link = module.vpc["${factory_key}/${vpc_key}"].self_link
project_id = module.projects[factory_key].id
custom_advertise = try(router_config.custom_advertise, {})
advertise_mode = try(router_config.custom_advertise != null, false) ? "CUSTOM" : "DEFAULT"
advertised_groups = try(router_config.custom_advertise.all_subnets, false) ? ["ALL_SUBNETS"] : []
keepalive = try(router_config.keepalive, null)
asn = try(router_config.asn, null)
})
}
]
]
])...)
vpns = merge(flatten([
for factory_key, factory_config in local.network_projects : [
for vpc_key, vpc_config in try(factory_config.vpc_config, {}) : [
for k, v in try(vpc_config.vpn_config, {}) : {
"${factory_key}/${vpc_key}/${k}" = merge(v, {
vpc_name = module.vpc["${factory_key}/${vpc_key}"].name
vpn_name = replace("${factory_key}/${vpc_key}/${k}", "/", "-")
project_id = module.projects[factory_key].id
},
{
router_config = merge(v.router_config,
try(v.router_config.create, false) == false && can(v.router_config.name) ? {
name = try(google_compute_router.default[v.router_config.name].name, v.router_config.name)
} : {}
)
}
)
}
]
]
])...)
}
resource "google_compute_router" "default" {
for_each = local.routers
name = replace(each.key, "/", "-")
project = each.value.project_id
region = each.value.region
network = each.value.vpc_self_link
bgp {
advertise_mode = each.value.advertise_mode
advertised_groups = each.value.advertised_groups
dynamic "advertised_ip_ranges" {
for_each = try(each.value.custom_advertise.ip_ranges, {})
iterator = range
content {
range = range.key
description = range.value
}
}
keepalive_interval = each.value.keepalive
asn = each.value.asn
}
}
resource "google_compute_ha_vpn_gateway" "default" {
for_each = local.vpns
project = each.value.project_id
region = each.value.region
name = replace(each.key, "/", "-")
network = each.value.vpc_name
stack_type = try(each.value.stack_type, null)
depends_on = [module.vpc]
}
module "vpn-ha" {
source = "../net-vpn-ha"
for_each = local.vpns
project_id = each.value.project_id
name = replace(each.key, "/", "-")
network = each.value.vpc_name
region = each.value.region
router_config = each.value.router_config
tunnels = each.value.tunnels
vpn_gateway = google_compute_ha_vpn_gateway.default[each.key].id
vpn_gateway_create = null
peer_gateways = {
for k, gw in each.value.peer_gateways : k => {
for gw_type, value in gw : gw_type => (
gw_type == "gcp" ? try(google_compute_ha_vpn_gateway.default[value].id, value) : value
)
}
}
}

View File

@@ -0,0 +1,38 @@
/**
* 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.
*/
# tfdoc:file:description Read and process YaML factory files and variables.
locals {
_network_factory_path = try(
pathexpand(var.factories_config.vpcs), null
)
_network_factory_files = try(
fileset(local._network_factory_path, "**/*.yaml"),
[]
)
_network_projects_from_files = {
for f in local._network_factory_files :
f => yamldecode(file("${local._network_factory_path}/${f}"))
}
_network_projects = {
for _, v in local._network_projects_from_files :
v.project_config.name => v
}
network_projects = merge(local._network_projects, var.network_project_config)
}

View File

@@ -0,0 +1,64 @@
/**
* 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.
*/
output "host_project_ids" {
description = "Network project ids."
value = { for k, v in module.projects : k => v.project_id }
}
output "host_project_numbers" {
description = "Network project numbers."
value = { for k, v in module.projects : k => v.number }
}
output "subnet_ids" {
description = "IDs of subnets created within each VPC."
value = { for k, v in module.vpc : k => v.subnet_ids }
}
output "subnet_proxy_only_self_links" {
description = "IDs of proxy-only subnets created within each VPC."
value = {
for k, v in module.vpc : k =>
{
for subnet_key, subnet_value in v.subnets_proxy_only : subnet_key => subnet_value.id
}
}
}
output "subnet_psc_self_links" {
description = "IDs of PSC subnets created within each VPC."
value = {
for k, v in module.vpc : k =>
{
for subnet_key, subnet_value in v.subnets_psc : subnet_key => subnet_value.id
}
}
}
output "vpc_self_links" {
description = "Self-links for the VPCs created on each project."
value = { for k, v in module.vpc : k => v.self_link }
}
output "vpn_gateway_endpoints" {
description = "External IP Addresses for the GCP VPN gateways."
value = { for k, v in google_compute_ha_vpn_gateway.default : k =>
{
for interface_key, interface_value in v.vpn_interfaces : interface_key => interface_value.ip_address
}
}
}

View File

@@ -0,0 +1,58 @@
# 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.
# yaml-language-server: $schema=../../schemas/network-project.schema.json
project_config:
name: net-dev-01
services:
- container.googleapis.com
- compute.googleapis.com
- dns.googleapis.com
- iap.googleapis.com
- networkmanagement.googleapis.com
- networksecurity.googleapis.com
- servicenetworking.googleapis.com
- stackdriver.googleapis.com
- vpcaccess.googleapis.com
shared_vpc_host_config:
enabled: true
vpc_config:
dev-spoke:
delete_default_routes_on_create: false
mtu: 1500
nat_config:
nat-ew8:
region: europe-west8
dns_zones:
root-peering:
zone_config:
domain: .
peering:
peer_network: net-land-01/hub
client_networks:
- net-dev-01/dev-spoke
subnets_factory_config:
subnets_folder: data/subnets/dev-spoke
firewall_factory_config:
rules_folder: data/firewall/dev-spoke
routes:
gateway:
dest_range: "8.8.8.8/32"
priority: 100
next_hop_type: "gateway"
next_hop: "default-internet-gateway"
ncc_config:
hub: net-land-01/hub
group: net-land-01/hub/default

View File

@@ -0,0 +1,109 @@
# 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.
# yaml-language-server: $schema=../../schemas/network-project.schema.json
project_config:
name: net-land-01
services:
- container.googleapis.com
- compute.googleapis.com
- dns.googleapis.com
- iap.googleapis.com
- networkmanagement.googleapis.com
- networksecurity.googleapis.com
- servicenetworking.googleapis.com
- stackdriver.googleapis.com
- vpcaccess.googleapis.com
shared_vpc_host_config:
enabled: true
ncc_hub_config:
name: hub
groups:
default:
auto_accept:
- net-prod-01
- net-dev-01
vpc_config:
test:
delete_default_routes_on_create: false
mtu: 1500
auto_create_subnetworks: true
hub:
delete_default_routes_on_create: false
mtu: 1500
routers:
vpn-router:
region: europe-west8
asn: 64514
dns_zones:
onprem-fwd:
zone_config:
domain: .
forwarding:
forwarders:
"8.8.8.8": default
"1.1.1.1": default
client_networks:
- net-land-01/hub
dot-test:
zone_config:
domain: test.
private:
client_networks:
- net-land-01/hub
recordsets:
"A localhost":
records: ["127.0.0.1"]
subnets_factory_config:
subnets_folder: data/subnets/hub
firewall_factory_config:
rules_folder: data/firewall/hub
routes:
gateway:
dest_range: "8.8.8.8/32"
priority: 100
next_hop_type: "gateway"
next_hop: "default-internet-gateway"
vpn_config:
to-onprem:
ncc_spoke_config:
hub: net-land-01/hub
region: europe-west8
peer_gateways:
default:
external:
redundancy_type: SINGLE_IP_INTERNALLY_REDUNDANT
interfaces:
- 8.8.8.8
router_config:
create: false
name: net-land-01/hub/vpn-router
tunnels:
remote-0:
bgp_peer:
address: 169.254.128.1
asn: 64513
bgp_session_range: "169.254.128.2/30"
peer_external_gateway_interface: 0
shared_secret: "mySecret"
vpn_gateway_interface: 0
remote-1:
bgp_peer:
address: 169.254.128.5
asn: 64513
bgp_session_range: "169.254.128.6/30"
peer_external_gateway_interface: 0
shared_secret: "mySecret"
vpn_gateway_interface: 1

View File

@@ -0,0 +1,58 @@
# 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.
# yaml-language-server: $schema=../../schemas/network-project.schema.json
project_config:
name: net-prod-01
services:
- container.googleapis.com
- compute.googleapis.com
- dns.googleapis.com
- iap.googleapis.com
- networkmanagement.googleapis.com
- networksecurity.googleapis.com
- servicenetworking.googleapis.com
- stackdriver.googleapis.com
- vpcaccess.googleapis.com
shared_vpc_host_config:
enabled: true
vpc_config:
prod-spoke:
delete_default_routes_on_create: false
mtu: 1500
nat_config:
nat-ew8:
region: europe-west8
dns_zones:
root-peering:
zone_config:
domain: .
peering:
peer_network: net-land-01/hub
client_networks:
- net-prod-01/prod-spoke
subnets_factory_config:
subnets_folder: data/subnets/prod-spoke
firewall_factory_config:
rules_folder: data/firewall/prod-spoke
routes:
gateway:
dest_range: "8.8.8.8/32"
priority: 100
next_hop_type: "gateway"
next_hop: "default-internet-gateway"
ncc_config:
hub: net-land-01/hub
group: net-land-01/hub/default

View File

@@ -0,0 +1,58 @@
# 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.
# yaml-language-server: $schema=../../schemas/network-project.schema.json
project_config:
name: net-dev-01
services:
- container.googleapis.com
- compute.googleapis.com
- dns.googleapis.com
- iap.googleapis.com
- networkmanagement.googleapis.com
- networksecurity.googleapis.com
- servicenetworking.googleapis.com
- stackdriver.googleapis.com
- vpcaccess.googleapis.com
shared_vpc_host_config:
enabled: true
vpc_config:
dev-spoke:
delete_default_routes_on_create: false
mtu: 1500
nat_config:
nat-ew8:
region: europe-west8
dns_zones:
root-peering:
zone_config:
domain: .
peering:
peer_network: net-land-01/hub
client_networks:
- net-dev-01/dev-spoke
subnets_factory_config:
subnets_folder: data/subnets/dev-spoke
firewall_factory_config:
rules_folder: data/firewall/dev-spoke
routes:
gateway:
dest_range: "8.8.8.8/32"
priority: 100
next_hop_type: "gateway"
next_hop: "default-internet-gateway"
peering_config:
to-hub:
peer_network: net-land-01/hub

View File

@@ -0,0 +1,113 @@
# 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.
# yaml-language-server: $schema=../../schemas/network-project.schema.json
project_config:
name: net-land-01
services:
- container.googleapis.com
- compute.googleapis.com
- dns.googleapis.com
- iap.googleapis.com
- networkmanagement.googleapis.com
- networksecurity.googleapis.com
- servicenetworking.googleapis.com
- stackdriver.googleapis.com
- vpcaccess.googleapis.com
shared_vpc_host_config:
enabled: true
vpc_config:
test:
delete_default_routes_on_create: false
mtu: 1500
auto_create_subnetworks: true
peering_config:
to-hub:
peer_network: net-land-01/hub
hub:
delete_default_routes_on_create: false
mtu: 1500
nat_config:
nat-ew8:
region: europe-west8
routers:
vpn-router:
region: europe-west8
asn: 64514
dns_zones:
onprem-fwd:
zone_config:
domain: .
forwarding:
forwarders:
"8.8.8.8": default
"1.1.1.1": default
client_networks:
- net-land-01/hub
dot-test:
zone_config:
domain: test.
private:
client_networks:
- net-land-01/hub
recordsets:
"A localhost":
records: ["127.0.0.1"]
subnets_factory_config:
subnets_folder: data/subnets/hub
firewall_factory_config:
rules_folder: data/firewall/hub
routes:
gateway:
dest_range: "8.8.8.8/32"
priority: 100
next_hop_type: "gateway"
next_hop: "default-internet-gateway"
peering_config:
to-prod:
peer_network: net-prod-01/prod-spoke
to-dev:
peer_network: net-dev-01/dev-spoke
to-test:
peer_network: net-land-01/test
vpn_config:
to-onprem:
region: europe-west8
peer_gateways:
default:
external:
redundancy_type: SINGLE_IP_INTERNALLY_REDUNDANT
interfaces:
- 8.8.8.8
router_config:
create: false
name: net-land-01/hub/vpn-router
tunnels:
remote-0:
bgp_peer:
address: 169.254.128.1
asn: 64513
bgp_session_range: "169.254.128.2/30"
peer_external_gateway_interface: 0
shared_secret: "mySecret"
vpn_gateway_interface: 0
remote-1:
bgp_peer:
address: 169.254.128.5
asn: 64513
bgp_session_range: "169.254.128.6/30"
peer_external_gateway_interface: 0
shared_secret: "mySecret"
vpn_gateway_interface: 1

View File

@@ -0,0 +1,58 @@
# 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.
# yaml-language-server: $schema=../../schemas/network-project.schema.json
project_config:
name: net-prod-01
services:
- container.googleapis.com
- compute.googleapis.com
- dns.googleapis.com
- iap.googleapis.com
- networkmanagement.googleapis.com
- networksecurity.googleapis.com
- servicenetworking.googleapis.com
- stackdriver.googleapis.com
- vpcaccess.googleapis.com
shared_vpc_host_config:
enabled: true
vpc_config:
prod-spoke:
delete_default_routes_on_create: false
mtu: 1500
nat_config:
nat-ew8:
region: europe-west8
dns_zones:
root-peering:
zone_config:
domain: .
peering:
peer_network: net-land-01/hub
client_networks:
- net-prod-01/prod-spoke
subnets_factory_config:
subnets_folder: data/subnets/prod-spoke
firewall_factory_config:
rules_folder: data/firewall/prod-spoke
routes:
gateway:
dest_range: "8.8.8.8/32"
priority: 100
next_hop_type: "gateway"
next_hop: "default-internet-gateway"
peering_config:
to-hub:
peer_network: net-land-01/hub

View File

@@ -0,0 +1,83 @@
# 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.
# yaml-language-server: $schema=../../schemas/network-project.schema.json
project_config:
name: net-dev-01
services:
- container.googleapis.com
- compute.googleapis.com
- dns.googleapis.com
- iap.googleapis.com
- networkmanagement.googleapis.com
- networksecurity.googleapis.com
- servicenetworking.googleapis.com
- stackdriver.googleapis.com
- vpcaccess.googleapis.com
shared_vpc_host_config:
enabled: true
vpc_config:
dev-spoke:
delete_default_routes_on_create: false
mtu: 1500
nat_config:
nat-ew8:
region: europe-west8
routers:
vpn-router:
region: europe-west8
asn: 64520
dns_zones:
root-peering:
zone_config:
domain: .
peering:
peer_network: net-land-01/hub
client_networks:
- net-dev-01/dev-spoke
subnets_factory_config:
subnets_folder: data/subnets/dev-spoke
firewall_factory_config:
rules_folder: data/firewall/dev-spoke
routes:
gateway:
dest_range: "8.8.8.8/32"
priority: 100
next_hop_type: "gateway"
next_hop: "default-internet-gateway"
vpn_config:
to-hub:
region: europe-west8
peer_gateways:
default:
gcp: net-land-01/hub/to-dev
router_config:
create: false
name: net-dev-01/dev-spoke/vpn-router
tunnels:
remote-0:
shared_secret: foobar
bgp_peer:
address: 169.254.2.1
asn: 64514
bgp_session_range: "169.254.2.2/30"
vpn_gateway_interface: 0
remote-1:
shared_secret: foobar
bgp_peer:
address: 169.254.2.5
asn: 64514
bgp_session_range: "169.254.2.6/30"
vpn_gateway_interface: 1

View File

@@ -0,0 +1,153 @@
# 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.
# yaml-language-server: $schema=../../schemas/network-project.schema.json
project_config:
name: net-land-01
services:
- container.googleapis.com
- compute.googleapis.com
- dns.googleapis.com
- iap.googleapis.com
- networkmanagement.googleapis.com
- networksecurity.googleapis.com
- servicenetworking.googleapis.com
- stackdriver.googleapis.com
- vpcaccess.googleapis.com
shared_vpc_host_config:
enabled: true
vpc_config:
test:
delete_default_routes_on_create: false
mtu: 1500
auto_create_subnetworks: true
hub:
delete_default_routes_on_create: false
mtu: 1500
nat_config:
nat-ew8:
region: europe-west8
routers:
vpn-router:
region: europe-west8
asn: 64514
custom_advertise:
all_subnets: false
ip_ranges:
"10.0.0.0/8": "rfc1918_10"
dns_zones:
onprem-fwd:
zone_config:
domain: .
forwarding:
forwarders:
"8.8.8.8": default
"1.1.1.1": default
client_networks:
- net-land-01/hub
dot-test:
zone_config:
domain: test.
private:
client_networks:
- net-land-01/hub
recordsets:
"A localhost":
records: ["127.0.0.1"]
subnets_factory_config:
subnets_folder: data/subnets/hub
firewall_factory_config:
rules_folder: data/firewall/hub
routes:
gateway:
dest_range: "8.8.8.8/32"
priority: 100
next_hop_type: "gateway"
next_hop: "default-internet-gateway"
vpn_config:
to-onprem:
region: europe-west8
peer_gateways:
default:
external:
redundancy_type: SINGLE_IP_INTERNALLY_REDUNDANT
interfaces:
- 8.8.8.8
router_config:
create: false
name: net-land-01/hub/vpn-router
tunnels:
remote-0:
bgp_peer:
address: 169.254.128.1
asn: 64513
bgp_session_range: "169.254.128.2/30"
peer_external_gateway_interface: 0
shared_secret: "mySecret"
vpn_gateway_interface: 0
remote-1:
bgp_peer:
address: 169.254.128.5
asn: 64513
bgp_session_range: "169.254.128.6/30"
peer_external_gateway_interface: 0
shared_secret: "mySecret"
vpn_gateway_interface: 1
to-dev:
region: europe-west8
peer_gateways:
default:
gcp: net-dev-01/dev-spoke/to-hub
router_config:
create: false
name: net-land-01/hub/vpn-router
tunnels:
remote-0:
shared_secret: foobar
bgp_peer:
address: 169.254.2.2
asn: 64520
bgp_session_range: "169.254.2.1/30"
vpn_gateway_interface: 0
remote-1:
shared_secret: foobar
bgp_peer:
address: 169.254.2.6
asn: 64520
bgp_session_range: "169.254.2.5/30"
vpn_gateway_interface: 1
to-prod:
region: europe-west8
peer_gateways:
default:
gcp: net-prod-01/prod-spoke/to-hub
router_config:
create: false
name: net-land-01/hub/vpn-router
tunnels:
remote-0:
shared_secret: foobar
bgp_peer:
address: 169.254.3.2
asn: 64523
bgp_session_range: "169.254.3.1/30"
vpn_gateway_interface: 0
remote-1:
shared_secret: foobar
bgp_peer:
address: 169.254.3.6
asn: 64523
bgp_session_range: "169.254.3.5/30"
vpn_gateway_interface: 1

View File

@@ -0,0 +1,83 @@
# 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.
# yaml-language-server: $schema=../../schemas/network-project.schema.json
project_config:
name: net-prod-01
services:
- container.googleapis.com
- compute.googleapis.com
- dns.googleapis.com
- iap.googleapis.com
- networkmanagement.googleapis.com
- networksecurity.googleapis.com
- servicenetworking.googleapis.com
- stackdriver.googleapis.com
- vpcaccess.googleapis.com
shared_vpc_host_config:
enabled: true
vpc_config:
prod-spoke:
delete_default_routes_on_create: false
mtu: 1500
nat_config:
nat-ew8:
region: europe-west8
routers:
vpn-router:
region: europe-west8
asn: 64523
dns_zones:
root-peering:
zone_config:
domain: .
peering:
peer_network: net-land-01/hub
client_networks:
- net-prod-01/prod-spoke
subnets_factory_config:
subnets_folder: data/subnets/prod-spoke
firewall_factory_config:
rules_folder: data/firewall/prod-spoke
routes:
gateway:
dest_range: "8.8.8.8/32"
priority: 100
next_hop_type: "gateway"
next_hop: "default-internet-gateway"
vpn_config:
to-hub:
region: europe-west8
peer_gateways:
default:
gcp: net-land-01/hub/to-prod
router_config:
create: false
name: net-prod-01/prod-spoke/vpn-router
tunnels:
remote-0:
shared_secret: foobar
bgp_peer:
address: 169.254.3.1
asn: 64514
bgp_session_range: "169.254.3.2/30"
vpn_gateway_interface: 0
remote-1:
shared_secret: foobar
bgp_peer:
address: 169.254.3.5
asn: 64514
bgp_session_range: "169.254.3.6/30"
vpn_gateway_interface: 1

View File

@@ -0,0 +1,28 @@
# 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.
# yaml-language-server: $schema=../../schemas/network-project.schema.json
project_config:
name: net-dev-01
services:
- container.googleapis.com
- compute.googleapis.com
- dns.googleapis.com
- iap.googleapis.com
- networkmanagement.googleapis.com
- networksecurity.googleapis.com
- servicenetworking.googleapis.com
- stackdriver.googleapis.com
- vpcaccess.googleapis.com

View File

@@ -0,0 +1,30 @@
# 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.
# yaml-language-server: $schema=../../schemas/network-project.schema.json
# This file creates an empty project, and exists to keep consistency with the other recipes.
project_config:
name: net-land-01
services:
- container.googleapis.com
- compute.googleapis.com
- dns.googleapis.com
- iap.googleapis.com
- networkmanagement.googleapis.com
- networksecurity.googleapis.com
- servicenetworking.googleapis.com
- stackdriver.googleapis.com
- vpcaccess.googleapis.com

View File

@@ -0,0 +1,28 @@
# 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.
# yaml-language-server: $schema=../../schemas/network-project.schema.json
project_config:
name: net-prod-01
services:
- container.googleapis.com
- compute.googleapis.com
- dns.googleapis.com
- iap.googleapis.com
- networkmanagement.googleapis.com
- networksecurity.googleapis.com
- servicenetworking.googleapis.com
- stackdriver.googleapis.com
- vpcaccess.googleapis.com

View File

@@ -0,0 +1,72 @@
# 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.
# yaml-language-server: $schema=../../schemas/network-project.schema.json
project_config:
name: net-dev-01
services:
- container.googleapis.com
- compute.googleapis.com
- dns.googleapis.com
- iap.googleapis.com
- networkmanagement.googleapis.com
- networksecurity.googleapis.com
- servicenetworking.googleapis.com
- stackdriver.googleapis.com
- vpcaccess.googleapis.com
shared_vpc_host_config:
enabled: true
vpc_config:
dev-spoke:
delete_default_routes_on_create: false
mtu: 1500
nat_config:
nat-ew8:
region: europe-west8
routers:
vpn-router:
region: europe-west8
asn: 64514
subnets_factory_config:
subnets_folder: data/subnets/dev-spoke
firewall_factory_config:
rules_folder: data/firewall/dev-spoke
routes:
gateway:
dest_range: "8.8.8.8/32"
priority: 100
next_hop_type: "gateway"
next_hop: "default-internet-gateway"
vpn_config:
to-onprem:
region: europe-west8
peer_gateways:
default:
external:
redundancy_type: SINGLE_IP_INTERNALLY_REDUNDANT
interfaces:
- 8.8.8.8
router_config:
create: false
name: net-dev-01/dev-spoke/vpn-router
tunnels:
remote-0:
bgp_peer:
address: 169.254.1.1
asn: 64513
bgp_session_range: "169.254.1.2/30"
peer_external_gateway_interface: 0
shared_secret: "mySecret"
vpn_gateway_interface: 0

View File

@@ -0,0 +1,30 @@
# 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.
# yaml-language-server: $schema=../../schemas/network-project.schema.json
# This file creates an empty project, and exists to keep consistency with the other recipes.
project_config:
name: net-land-01
services:
- container.googleapis.com
- compute.googleapis.com
- dns.googleapis.com
- iap.googleapis.com
- networkmanagement.googleapis.com
- networksecurity.googleapis.com
- servicenetworking.googleapis.com
- stackdriver.googleapis.com
- vpcaccess.googleapis.com

View File

@@ -0,0 +1,72 @@
# 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.
# yaml-language-server: $schema=../../schemas/network-project.schema.json
project_config:
name: net-prod-01
services:
- container.googleapis.com
- compute.googleapis.com
- dns.googleapis.com
- iap.googleapis.com
- networkmanagement.googleapis.com
- networksecurity.googleapis.com
- servicenetworking.googleapis.com
- stackdriver.googleapis.com
- vpcaccess.googleapis.com
shared_vpc_host_config:
enabled: true
vpc_config:
prod-spoke:
delete_default_routes_on_create: false
mtu: 1500
nat_config:
nat-ew8:
region: europe-west8
routers:
vpn-router:
region: europe-west8
asn: 64514
subnets_factory_config:
subnets_folder: data/subnets/prod-spoke
firewall_factory_config:
rules_folder: data/firewall/prod-spoke
routes:
gateway:
dest_range: "8.8.8.8/32"
priority: 100
next_hop_type: "gateway"
next_hop: "default-internet-gateway"
vpn_config:
to-onprem:
region: europe-west8
peer_gateways:
default:
external:
redundancy_type: SINGLE_IP_INTERNALLY_REDUNDANT
interfaces:
- 8.8.8.8
router_config:
create: false
name: net-prod-01/prod-spoke/vpn-router
tunnels:
remote-0:
bgp_peer:
address: 169.254.1.1
asn: 64513
bgp_session_range: "169.254.1.2/30"
peer_external_gateway_interface: 0
shared_secret: "mySecret"
vpn_gateway_interface: 0

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,382 @@
/**
* 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.
*/
variable "billing_account" {
description = "Billing account id."
type = string
}
variable "factories_config" {
description = "Configuration for network resource factories."
type = object({
vpcs = optional(string, "recipes/hub-and-spoke-ncc")
firewall_policy_name = optional(string, "net-default")
})
default = {
vpcs = "recipes/hub-and-spoke-ncc"
}
}
variable "network_project_config" {
description = "Consolidated configuration for project, VPCs and their associated resources."
type = map(object({
project_config = object({
name = string
prefix = optional(string)
parent = optional(string)
billing_account = optional(string)
deletion_policy = optional(string, "DELETE")
default_service_account = optional(string, "keep")
auto_create_network = optional(bool, false)
project_create = optional(bool, true)
shared_vpc_host_config = optional(object({
enabled = bool
service_projects = optional(list(string), [])
}))
services = optional(list(string), )
org_policies = optional(map(object({
inherit_from_parent = optional(bool)
reset = optional(bool)
rules = optional(list(object({
allow = optional(object({
all = optional(bool)
values = optional(list(string))
}))
deny = optional(object({
all = optional(bool)
values = optional(list(string))
}))
enforce = optional(bool)
condition = optional(object({
description = optional(string)
expression = optional(string)
location = optional(string)
title = optional(string)
}), {})
})), )
})), {})
metric_scopes = optional(list(string), [])
iam = optional(map(list(string)), {})
iam_bindings = optional(map(object({
members = list(string)
role = string
condition = optional(object({
expression = string
title = string
description = optional(string)
}))
})), {})
iam_bindings_additive = optional(map(object({
member = string
role = string
condition = optional(object({
expression = string
title = string
description = optional(string)
}))
})), {})
iam_by_principals_additive = optional(map(list(string)), {})
iam_by_principals = optional(map(list(string)), {})
})
ncc_hub_config = optional(object({
name = string
description = optional(string, "Terraform-managed.")
preset_topology = optional(string, "MESH")
export_psc = optional(bool, true)
groups = optional(map(object({
labels = optional(map(string))
description = optional(string, "Terraform-managed.")
auto_accept = optional(list(string), [])
})))
}))
vpc_config = optional(map(object({
auto_create_subnetworks = optional(bool, false)
create_googleapis_routes = optional(object({
private = optional(bool, true)
private-6 = optional(bool, false)
restricted = optional(bool, true)
restricted-6 = optional(bool, false)
}), {})
delete_default_routes_on_create = optional(bool, false)
description = optional(string, "Terraform-managed.")
dns_policy = optional(object({
inbound = optional(bool)
logging = optional(bool)
outbound = optional(object({
private_ns = list(string)
public_ns = list(string)
}))
}))
dns_zones = optional(map(object({
force_destroy = optional(bool)
description = optional(string, "Terraform managed.")
iam = optional(map(list(string)), {})
zone_config = object({
domain = string
forwarding = optional(object({
forwarders = optional(map(string), {})
client_networks = optional(list(string), )
}))
peering = optional(object({
client_networks = optional(list(string), )
peer_network = string
}))
public = optional(object({
dnssec_config = optional(object({
non_existence = optional(string, "nsec3")
state = string
key_signing_key = optional(object(
{ algorithm = string, key_length = number }),
{ algorithm = "rsasha256", key_length = 2048 }
)
zone_signing_key = optional(object(
{ algorithm = string, key_length = number }),
{ algorithm = "rsasha256", key_length = 1024 }
)
}))
enable_logging = optional(bool, false)
}))
private = optional(object({
client_networks = optional(list(string), )
service_directory_namespace = optional(string)
}))
})
recordsets = optional(map(object({
ttl = optional(number, 300)
records = optional(list(string))
geo_routing = optional(list(object({
location = string
records = optional(list(string))
health_checked_targets = optional(list(object({
load_balancer_type = string
ip_address = string
port = string
ip_protocol = string
network_url = string
project = string
region = optional(string)
})))
})))
wrr_routing = optional(list(object({
weight = number
records = list(string)
})))
})), {})
})))
firewall_policy_enforcement_order = optional(string, "AFTER_CLASSIC_FIREWALL")
ipv6_config = optional(object({
enable_ula_internal = optional(bool)
internal_range = optional(string)
}), {})
mtu = optional(number)
name = string
nat_config = optional(map(object({
region = string
router_create = optional(bool, true)
router_name = optional(string)
router_network = optional(string)
router_asn = optional(number)
type = optional(string, "PUBLIC")
addresses = optional(list(string), [])
endpoint_types = optional(list(string))
logging_filter = optional(string)
config_port_allocation = optional(object({
enable_endpoint_independent_mapping = optional(bool, true)
enable_dynamic_port_allocation = optional(bool, false)
min_ports_per_vm = optional(number)
max_ports_per_vm = optional(number, 65536)
}), {})
config_source_subnetworks = optional(object({
all = optional(bool, true)
primary_ranges_only = optional(bool)
subnetworks = optional(list(object({
self_link = string
all_ranges = optional(bool, true)
primary_range = optional(bool, false)
secondary_ranges = optional(list(string))
})), [])
}), {})
config_timeouts = optional(object({
icmp = optional(number)
tcp_established = optional(number)
tcp_time_wait = optional(number)
tcp_transitory = optional(number)
udp = optional(number)
}), {})
rules = optional(list(object({
description = optional(string)
match = string
source_ips = optional(list(string))
source_ranges = optional(list(string))
})), [])
})))
network_attachments = optional(map(object({
subnet = string
automatic_connection = optional(bool, false)
description = optional(string, "Terraform-managed.")
producer_accept_lists = optional(list(string))
producer_reject_lists = optional(list(string))
})), {})
policy_based_routes = optional(map(object({
description = optional(string, "Terraform-managed.")
labels = optional(map(string))
priority = optional(number)
next_hop_ilb_ip = optional(string)
use_default_routing = optional(bool, false)
filter = optional(object({
ip_protocol = optional(string)
dest_range = optional(string)
src_range = optional(string)
}), {})
target = optional(object({
interconnect_attachment = optional(string)
tags = optional(list(string))
}), {})
})), {})
psa_config = optional(list(object({
deletion_policy = optional(string, null)
ranges = map(string)
export_routes = optional(bool, false)
import_routes = optional(bool, false)
peered_domains = optional(list(string), [])
range_prefix = optional(string)
service_producer = optional(string, "servicenetworking.googleapis.com")
})), [])
routers = optional(map(object({
region = string
asn = optional(number)
custom_advertise = optional(object({
all_subnets = bool
ip_ranges = map(string)
}))
keepalive = optional(number)
name = optional(string)
})))
routes = optional(map(object({
description = optional(string, "Terraform-managed.")
dest_range = string
next_hop_type = string
next_hop = string
priority = optional(number)
tags = optional(list(string))
})), {})
routing_mode = optional(string, "GLOBAL")
subnets_factory_config = optional(object({
context = optional(object({
regions = optional(map(string), {})
}), {})
subnets_folder = optional(string)
}), {})
firewall_factory_config = optional(object({
cidr_tpl_file = optional(string)
rules_folder = optional(string)
}), {})
vpn_config = optional(map(object({
#TOFIX: are we even using name?
name = string
region = string
ncc_spoke_config = optional(object({
hub = string
description = string
labels = map(string)
}))
peer_gateways = map(object({
external = optional(object({
redundancy_type = string
interfaces = list(string)
description = optional(string, "Terraform managed external VPN gateway")
name = optional(string)
}))
gcp = optional(string)
}))
router_config = object({
asn = optional(number)
create = optional(bool, true)
custom_advertise = optional(object({
all_subnets = bool
ip_ranges = map(string)
}))
keepalive = optional(number)
name = optional(string)
override_name = optional(string)
})
stack_type = optional(string)
tunnels = map(object({
bgp_peer = object({
address = string
asn = number
route_priority = optional(number, 1000)
custom_advertise = optional(object({
all_subnets = bool
ip_ranges = map(string)
}))
md5_authentication_key = optional(object({
name = string
key = optional(string)
}))
ipv6 = optional(object({
nexthop_address = optional(string)
peer_nexthop_address = optional(string)
}))
name = optional(string)
})
# each BGP session on the same Cloud Router must use a unique /30 CIDR
# from the 169.254.0.0/16 block.
bgp_session_range = string
ike_version = optional(number, 2)
name = optional(string)
peer_external_gateway_interface = optional(number)
peer_router_interface_name = optional(string)
peer_gateway = optional(string, "default")
router = optional(string)
shared_secret = optional(string)
vpn_gateway_interface = number
}))
})), {})
peering_config = optional(map(object({
peer_network = string
routes_config = optional(object({
export = optional(bool, true)
import = optional(bool, true)
public_export = optional(bool)
public_import = optional(bool)
}
), {})
stack_type = optional(string)
})), {})
ncc_config = optional(object({
hub = string
description = optional(string, "Terraform-managed.")
labels = optional(map(string))
group = optional(string)
exclude_export_ranges = optional(list(string), null)
include_export_ranges = optional(list(string), null)
}))
})))
}))
default = null
}
variable "parent_id" {
description = "Root node for the projects created by the factory. Must be either organizations/XXXXXXXX or folders/XXXXXXXX."
type = string
}
variable "prefix" {
description = "Prefix used for projects."
type = string
}

View File

@@ -0,0 +1,3 @@
billing_account = "123456-789012-345678"
parent_id = "folders/123456789012"
prefix = "myprefix"

View File

@@ -0,0 +1,2 @@
factories_config = { vpcs = "recipes/hub-and-spoke-ncc" }

View File

@@ -0,0 +1,40 @@
# 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.
counts:
google_compute_external_vpn_gateway: 1
google_compute_firewall: 9
google_compute_ha_vpn_gateway: 1
google_compute_network: 4
google_compute_route: 15
google_compute_router: 3
google_compute_router_interface: 2
google_compute_router_nat: 2
google_compute_router_peer: 2
google_compute_shared_vpc_host_project: 3
google_compute_subnetwork: 3
google_compute_vpn_tunnel: 2
google_dns_managed_zone: 4
google_dns_policy: 4
google_dns_record_set: 1
google_network_connectivity_group: 1
google_network_connectivity_hub: 1
google_network_connectivity_spoke: 3
google_project: 3
google_project_iam_member: 21
google_project_service: 27
google_project_service_identity: 21
modules: 17
random_id: 3
resources: 136

View File

@@ -0,0 +1,2 @@
factories_config = { vpcs = "recipes/only-projects" }

View File

@@ -0,0 +1,21 @@
# 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.
counts:
google_project: 3
google_project_iam_member: 21
google_project_service: 27
google_project_service_identity: 21
modules: 3
resources: 72

View File

@@ -0,0 +1,2 @@
factories_config = { vpcs = "recipes/hub-and-spoke-peering" }

View File

@@ -0,0 +1,38 @@
# 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.
counts:
google_compute_external_vpn_gateway: 1
google_compute_firewall: 9
google_compute_ha_vpn_gateway: 1
google_compute_network: 4
google_compute_network_peering: 6
google_compute_route: 15
google_compute_router: 4
google_compute_router_interface: 2
google_compute_router_nat: 3
google_compute_router_peer: 2
google_compute_shared_vpc_host_project: 3
google_compute_subnetwork: 3
google_compute_vpn_tunnel: 2
google_dns_managed_zone: 4
google_dns_policy: 4
google_dns_record_set: 1
google_project: 3
google_project_iam_member: 21
google_project_service: 27
google_project_service_identity: 21
modules: 18
random_id: 3
resources: 139

View File

@@ -0,0 +1,2 @@
factories_config = { vpcs = "recipes/separate-envs" }

View File

@@ -0,0 +1,35 @@
# 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.
counts:
google_compute_external_vpn_gateway: 2
google_compute_firewall: 6
google_compute_ha_vpn_gateway: 2
google_compute_network: 2
google_compute_route: 8
google_compute_router: 4
google_compute_router_interface: 2
google_compute_router_nat: 2
google_compute_router_peer: 2
google_compute_shared_vpc_host_project: 2
google_compute_subnetwork: 2
google_compute_vpn_tunnel: 2
google_dns_policy: 2
google_project: 3
google_project_iam_member: 21
google_project_service: 27
google_project_service_identity: 21
modules: 11
random_id: 4
resources: 114

View File

@@ -0,0 +1,23 @@
# 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.
module: modules/net-vpc-factory
common_tfvars:
- common.tfvars
tests:
ncc:
only_projects:
peering:
separate_envs:
vpn:

View File

@@ -0,0 +1 @@
factories_config = { vpcs = "recipes/hub-and-spoke-vpn" }

View File

@@ -0,0 +1,37 @@
# 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.
counts:
google_compute_external_vpn_gateway: 1
google_compute_firewall: 9
google_compute_ha_vpn_gateway: 5
google_compute_network: 4
google_compute_route: 15
google_compute_router: 6
google_compute_router_interface: 10
google_compute_router_nat: 3
google_compute_router_peer: 10
google_compute_shared_vpc_host_project: 3
google_compute_subnetwork: 3
google_compute_vpn_tunnel: 10
google_dns_managed_zone: 4
google_dns_policy: 4
google_dns_record_set: 1
google_project: 3
google_project_iam_member: 21
google_project_service: 27
google_project_service_identity: 21
modules: 22
random_id: 15
resources: 175