* exposing the network_id from the net-vpc module for use with tag bindings * convert vpc_create to vpc_reuse * Changed the reuse vars to standardised attributes * fixed readme tests and schemas * modified apigee blueprint to use vpc_reuse with network_id passthrough --------- Co-authored-by: Ludovico Magnocavallo <ludomagno@google.com>
833 lines
46 KiB
Markdown
833 lines
46 KiB
Markdown
# Networking Factory
|
|
|
|
The factory is implemented as a thin data translation layer for the underlying modules, so that no "magic" or hidden side effects are implemented in code, and debugging or integration of new features are simple.
|
|
|
|
The code is meant to be executed by a service account or a user with a wide set of permissions:
|
|
|
|
- roles/resourcemanager.projectCreator (only if creating projects)
|
|
- roles/billing.user (only if creating projects)
|
|
- roles/resourcemanager.folderViewer (if parent is folder)
|
|
- roles/orgpolicy.policyAdmin (at the organization level, in case you're configuring Org Policies)
|
|
- roles/compute.xpnAdmin (at the parent folder level, if Shared VPC is used)
|
|
|
|
This factory module acts as a wrapper around several core Terraform modules:
|
|
|
|
- [`../project`](../project/): For managing GCP projects.
|
|
- [`../net-vpc`](../net-vpc): For managing VPC networks, subnets, routes, PSA, etc.
|
|
- [`../net-vpc-firewall`](../net-vpc-firewall/): For managing VPC firewall rules.
|
|
- [`../net-vpn-ha`](../net-vpn-ha): For managing Cloud HA VPN connections.
|
|
- [`../net-cloudnat`](../net-cloudnat/): For managing Cloud NAT instances.
|
|
- [`../dns`](../dns): For managing Cloud DNS zones and record sets.
|
|
|
|
## TOC
|
|
|
|
<!-- BEGIN TOC -->
|
|
- [TOC](#toc)
|
|
- [Factory configuration](#factory-configuration)
|
|
- [Configuration Methods](#configuration-methods)
|
|
- [Cross-Referencing Resources](#cross-referencing-resources)
|
|
- [Projects](#projects)
|
|
- [VPCs](#vpcs)
|
|
- [Subnets](#subnets)
|
|
- [Firewall Rules](#firewall-rules)
|
|
- [Cloud NAT](#cloud-nat)
|
|
- [Routes](#routes)
|
|
- [Private Service Access (PSA)](#private-service-access-psa)
|
|
- [VPC DNS Policy](#vpc-dns-policy)
|
|
- [Connectivity](#connectivity)
|
|
- [VPC Peering](#vpc-peering)
|
|
- [Cloud VPN](#cloud-vpn)
|
|
- [GCP to OnPrem](#gcp-to-onprem)
|
|
- [GCP to GCP VPN](#gcp-to-gcp-vpn)
|
|
- [Network Connectivity Center (NCC)](#network-connectivity-center-ncc)
|
|
- [NCC VPC Spokes](#ncc-vpc-spokes)
|
|
- [NCC VPN Spokes](#ncc-vpn-spokes)
|
|
- [DNS](#dns)
|
|
- [Private Zone](#private-zone)
|
|
- [Forwarding Zone](#forwarding-zone)
|
|
- [Peering Zone](#peering-zone)
|
|
- [Public Zone with DNSSEC](#public-zone-with-dnssec)
|
|
- [Variables](#variables)
|
|
- [Outputs](#outputs)
|
|
<!-- END TOC -->
|
|
|
|
## Factory configuration
|
|
|
|
At a high level, the factory consumes all YAML files in a directory (whose path is `var.factories_config.vpcs`).
|
|
Each file defines a single project, which can either be created by the factory or pre-created externally, and all the network infrastructure to be deployed in that project, including
|
|
|
|
- Project
|
|
- NCC Hubs
|
|
- VPCs
|
|
- Connectivity (including VPNs, VPC peerings, NCC VPC Spokes and NCC VPN hybrid spokes)
|
|
- DNS policies
|
|
- DNS zones
|
|
- Firewall rules/policies (via a sub-factory)
|
|
- NAT (public or private)
|
|
- PSA configuration
|
|
- Routes (including PBRs)
|
|
- Subnets (via a sub-factory)
|
|
|
|
### Configuration Methods
|
|
|
|
- **YAML Factory:** The primary method is to define project and network configurations within individual YAML files placed in the directory specified by `var.factories_config.vpcs`. This factory approach allows for modular and organized management of complex setups.
|
|
- **Direct Variable Input (Discouraged):** The module also defines `var.network_project_config`. While it's *technically possible* to populate this variable directly in a .tfvars file, this is **not the recommended approach**. It bypasses the intended factory pattern and makes managing multiple project configurations cumbersome. The variable definition primarily serves as **documentation** for the structure expected within the YAML configuration files.
|
|
|
|
### Cross-Referencing Resources
|
|
|
|
A key capability of this factory is establishing relationships between resources defined across different VPCs or projects. This is achieved through cross-referencing using logical keys within the YAML configuration. These keys strictly follow the pattern `project_key/vpc_key/resource_key` for resources like VPCs, VPN gateways, routers, or NCC hubs/groups. During Terraform execution, the factory code translates these logical keys into the actual resource IDs or self-links required by the underlying modules. This mechanism avoids hardcoding resource IDs and enables the declarative definition of complex topologies. It's extensively used in configurations for:
|
|
|
|
VPC Peering: Specifying the peer_network (e.g., `peer_network: net-land-01/hub`).
|
|
|
|
DNS Peering/Forwarding: Defining peer_network or client_networks for DNS zones (e.g., `client_networks: [net-dev-01/dev-spoke]`).
|
|
|
|
GCP-to-GCP HA VPN: Referencing the peer HA VPN gateway using its logical key (e.g., `peer_gateways.default.gcp: net-dev-01/dev-spoke/to-hub`).
|
|
|
|
Network Connectivity Center (NCC): Linking spokes to hubs (`ncc_config.hub: net-land-01/hub`) and groups (`ncc_config.group: net-land-01/hub/default`), or auto-accepting spokes in hub groups (`auto_accept: [net-prod-01, net-dev-01]`).
|
|
|
|
## Projects
|
|
|
|
The `project_config` block within each YAML file implements a large subset of the [project module](../project/) variable interface, which allows for project creation or reuse, services enablement and IAM/Organization policies definition.
|
|
|
|
Below is a valid YAML file which simply creates a project, enables a minimal set of services, configures the project as a host project, adds an authoritative
|
|
role binding and sets an Organization Policy at the project level:
|
|
|
|
```hcl
|
|
module "net-vpc-factory" {
|
|
source = "./fabric/modules/net-vpc-factory"
|
|
billing_account = "123456-789012-345678"
|
|
parent_id = "folders/123456789012"
|
|
prefix = "myprefix"
|
|
factories_config = { vpcs = "recipes/examples" }
|
|
}
|
|
# tftest files=project-config
|
|
```
|
|
|
|
```yaml
|
|
project_config:
|
|
name: project-config
|
|
services:
|
|
- compute.googleapis.com
|
|
- dns.googleapis.com
|
|
- networkmanagement.googleapis.com
|
|
- networksecurity.googleapis.com
|
|
- servicenetworking.googleapis.com
|
|
- stackdriver.googleapis.com
|
|
- vpcaccess.googleapis.com
|
|
shared_vpc_host_config:
|
|
enabled: true
|
|
iam:
|
|
roles/owner:
|
|
- group:prj-admins@example.com
|
|
org_policies:
|
|
compute.restrictLoadBalancerCreationForTypes:
|
|
rules:
|
|
- allow:
|
|
values:
|
|
- EXTERNAL_HTTP_HTTPS
|
|
# tftest-file id=project-config path=recipes/examples/project-config.yaml schema=network-project.schema.json
|
|
```
|
|
|
|
## VPCs
|
|
|
|
The `vpc_config` block within each project's YAML file defines one or more VPCs to be created in that project. It implements a large subset of the [net-vpc module](../net-vpc/) variable interface, allowing for the creation of VPCs, subnets, routes, etc.
|
|
|
|
Below is a valid YAML file excerpt with a minimal set of configurations creating a project and two VPCs, and pointing to sub-factories for subnets and firewall rules:
|
|
|
|
```hcl
|
|
module "net-vpc-factory" {
|
|
source = "./fabric/modules/net-vpc-factory"
|
|
billing_account = "123456-789012-345678"
|
|
parent_id = "folders/123456789012"
|
|
prefix = "myprefix"
|
|
factories_config = { vpcs = "recipes/examples" }
|
|
}
|
|
# tftest files=vpc-config
|
|
```
|
|
|
|
```yaml
|
|
project_config:
|
|
name: vpc-config
|
|
services:
|
|
- compute.googleapis.com
|
|
vpc_config:
|
|
net-00:
|
|
subnets_factory_config:
|
|
subnets_folder: data/subnets/net-00
|
|
firewall_factory_config:
|
|
rules_folder: data/firewall/net-00
|
|
# tftest-file id=vpc-config path=recipes/examples/vpc-config.yaml schema=network-project.schema.json
|
|
```
|
|
|
|
### Subnets
|
|
|
|
Subnets are managed via the `vpc_config.<vpc_name>.subnets_factory_config` parameter within the project's YAML file. This leverages the [`net-vpc`](../net-vpc/) module for subnet creation and management. Please refer to its documentation for detailed information on subnet configuration options and the expected YAML structure within the subnets_folder.
|
|
|
|
### Firewall Rules
|
|
|
|
Firewall rules are managed via the `vpc_config.<vpc_name>.firewall_factory_config` parameter, which leverages the [net-vpc-firewall](../net-vpc-firewall/) module for firewall rule creation and management. Please refer to its documentation for detailed information on firewall rule configuration options and the expected YAML structure within the rules_folder.
|
|
|
|
### Cloud NAT
|
|
|
|
Cloud NAT is configured via the `vpc_config.<vpc_name>.nat_config` block. This uses the [net-cloudnat](../net-cloudnat/) module.
|
|
|
|
```hcl
|
|
module "net-vpc-factory" {
|
|
source = "./fabric/modules/net-vpc-factory"
|
|
billing_account = "123456-789012-345678"
|
|
parent_id = "folders/123456789012"
|
|
prefix = "myprefix"
|
|
factories_config = { vpcs = "recipes/examples" }
|
|
}
|
|
# tftest files=nat-config
|
|
```
|
|
|
|
```yaml
|
|
project_config:
|
|
name: nat-config
|
|
services:
|
|
- compute.googleapis.com
|
|
vpc_config:
|
|
net-00:
|
|
delete_default_routes_on_create: false
|
|
nat_config:
|
|
nat-ew8:
|
|
region: europe-west8
|
|
subnets_factory_config:
|
|
subnets_folder: data/subnets/foobar
|
|
firewall_factory_config:
|
|
rules_folder: data/firewall/foobar
|
|
# tftest-file id=nat-config path=recipes/examples/nat-config.yaml schema=network-project.schema.json
|
|
```
|
|
|
|
### Routes
|
|
|
|
Static routes and Policy-Based Routes (PBRs) are configured within the `vpc_config.<vpc_name>.routes` and `vpc_config.<vpc_name>.policy_based_routes` blocks.
|
|
|
|
```hcl
|
|
module "net-vpc-factory" {
|
|
source = "./fabric/modules/net-vpc-factory"
|
|
billing_account = "123456-789012-345678"
|
|
parent_id = "folders/123456789012"
|
|
prefix = "myprefix"
|
|
factories_config = { vpcs = "recipes/examples" }
|
|
}
|
|
# tftest files=routes-config
|
|
```
|
|
|
|
```yaml
|
|
project_config:
|
|
name: routes-config
|
|
services:
|
|
- compute.googleapis.com
|
|
vpc_config:
|
|
net-00:
|
|
routes:
|
|
default-internet:
|
|
dest_range: 0.0.0.0/0
|
|
next_hop_type: gateway
|
|
next_hop: default-internet-gateway
|
|
priority: 1000
|
|
policy_based_routes:
|
|
pbr-to-nva:
|
|
filter:
|
|
src_range: 10.0.1.0/24
|
|
dest_range: 0.0.0.0/0
|
|
next_hop_ilb_ip: 10.0.100.5
|
|
priority: 100
|
|
# tftest-file id=routes-config path=recipes/examples/routes-config.yaml schema=network-project.schema.json
|
|
```
|
|
|
|
Refer to the [net-vpc](../net-vpc/) module documentation for details on routes and policy_based_routes.
|
|
|
|
### Private Service Access (PSA)
|
|
|
|
PSA configuration is managed via `vpc_config.<vpc_name>.psa_config`.
|
|
|
|
```hcl
|
|
module "net-vpc-factory" {
|
|
source = "./fabric/modules/net-vpc-factory"
|
|
billing_account = "123456-789012-345678"
|
|
parent_id = "folders/123456789012"
|
|
prefix = "myprefix"
|
|
factories_config = { vpcs = "recipes/examples" }
|
|
}
|
|
# tftest files=psa-config
|
|
```
|
|
|
|
```yaml
|
|
project_config:
|
|
name: psa-config
|
|
services:
|
|
- compute.googleapis.com
|
|
vpc_config:
|
|
net-00:
|
|
psa_config:
|
|
- ranges:
|
|
global-psa-range: 10.100.0.0/24
|
|
peered_domains: ["onprem.example."]
|
|
# tftest-file id=psa-config path=recipes/examples/psa-config.yaml schema=network-project.schema.json
|
|
```
|
|
|
|
Refer to the [net-vpc](../net-vpc) module documentation for details on psa_config.
|
|
|
|
### VPC DNS Policy
|
|
|
|
Configure VPC-level DNS behavior, such as enabling inbound query forwarding or logging, using the `dns_policy` block.
|
|
|
|
```hcl
|
|
module "net-vpc-factory" {
|
|
source = "./fabric/modules/net-vpc-factory"
|
|
billing_account = "123456-789012-345678"
|
|
parent_id = "folders/123456789012"
|
|
prefix = "myprefix"
|
|
factories_config = { vpcs = "recipes/examples" }
|
|
}
|
|
# tftest files=vpc-dns-policy
|
|
```
|
|
|
|
```yaml
|
|
project_config:
|
|
name: vpc-dns-policy
|
|
services:
|
|
- compute.googleapis.com
|
|
- dns.googleapis.com
|
|
vpc_config:
|
|
net-dns-policy-demo:
|
|
dns_policy:
|
|
inbound: true
|
|
logging: true
|
|
# tftest-file id=vpc-dns-policy path=recipes/examples/vpc-dns-policy.yaml schema=network-project.schema.json
|
|
```
|
|
|
|
## Connectivity
|
|
|
|
This module supports various connectivity options:
|
|
|
|
### VPC Peering
|
|
|
|
The example below implements a Hub-and-spoke design, where spokes are connected to the Hub via VPC Peerings:
|
|
|
|
```hcl
|
|
module "net-vpc-factory" {
|
|
source = "./fabric/modules/net-vpc-factory"
|
|
billing_account = "123456-789012-345678"
|
|
parent_id = "folders/123456789012"
|
|
prefix = "myprefix"
|
|
factories_config = { vpcs = "recipes/examples" }
|
|
}
|
|
# tftest files=peerings-hub,peerings-dev,peerings-prod
|
|
```
|
|
|
|
Hub:
|
|
|
|
```yaml
|
|
project_config:
|
|
name: net-land-01
|
|
services:
|
|
- compute.googleapis.com
|
|
vpc_config:
|
|
hub:
|
|
peering_config:
|
|
to-prod:
|
|
peer_network: net-prod-01/prod-spoke
|
|
to-dev:
|
|
peer_network: net-dev-01/dev-spoke
|
|
stack_type: IPV4_IPV6
|
|
|
|
# tftest-file id=peerings-hub path=recipes/examples/net-land-01.yaml schema=network-project.schema.json
|
|
```
|
|
|
|
Dev Spoke:
|
|
|
|
```yaml
|
|
project_config:
|
|
name: net-dev-01
|
|
services:
|
|
- compute.googleapis.com
|
|
vpc_config:
|
|
dev-spoke:
|
|
peering_config:
|
|
to-hub:
|
|
peer_network: net-land-01/hub
|
|
stack_type: IPV4_IPV6
|
|
|
|
# tftest-file id=peerings-dev path=recipes/examples/net-dev-01.yaml schema=network-project.schema.json
|
|
```
|
|
|
|
Prod Spoke:
|
|
|
|
```yaml
|
|
project_config:
|
|
name: net-prod-01
|
|
services:
|
|
- compute.googleapis.com
|
|
vpc_config:
|
|
prod-spoke:
|
|
peering_config:
|
|
to-hub:
|
|
peer_network: net-land-01/hub
|
|
|
|
# tftest-file id=peerings-prod path=recipes/examples/net-prod-01.yaml schema=network-project.schema.json
|
|
```
|
|
|
|
### Cloud VPN
|
|
|
|
The example below implements a Hub-and-spoke design, where spokes are connected to the Hub via HA-VPN:
|
|
|
|
#### GCP to OnPrem
|
|
|
|
This example demonstrates connecting an on-premises network to GCP via HA-VPN. The `vpn_config` implements the same interface as module [net-vpn-ha](../net-vpn-ha/).
|
|
|
|
In this example, the configuration `vpc_config.net-00.routers` creates a router named `vpn-router` in europe-west8, and `vpc_config.net-00.vpn_config.to-onprem.router_config.name` refers to it, using the key `<project_key>/<vpc_key>/<router_key>` (e.g., prj-01/net-00/vpn-router.
|
|
Per module `net-vpn-ha`, omitting the `router_config` configuration results in the router being automatically created and managed by the VPN module itself.
|
|
|
|
Note that - given the limit of 5 Cloud Routers per VPC per region - we recommend creating routers as required and using them across multiple VPNs/Interconnects by setting and referencing the pre-created router.
|
|
|
|
```hcl
|
|
module "net-vpc-factory" {
|
|
source = "./fabric/modules/net-vpc-factory"
|
|
billing_account = "123456-789012-345678"
|
|
parent_id = "folders/123456789012"
|
|
prefix = "myprefix"
|
|
factories_config = { vpcs = "recipes/examples" }
|
|
}
|
|
# tftest files=vpn-config
|
|
```
|
|
|
|
```yaml
|
|
project_config:
|
|
name: prj-01
|
|
services:
|
|
- compute.googleapis.com
|
|
vpc_config:
|
|
net-00:
|
|
routers:
|
|
vpn-router:
|
|
region: europe-west8
|
|
asn: 64514
|
|
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: prj-01/net-00/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
|
|
remote-1:
|
|
bgp_peer:
|
|
address: 169.254.2.1
|
|
asn: 64513
|
|
bgp_session_range: "169.254.2.2/30"
|
|
peer_external_gateway_interface: 0
|
|
shared_secret: "mySecret"
|
|
vpn_gateway_interface: 1
|
|
# tftest-file id=vpn-config path=recipes/examples/vpn-config.yaml schema=network-project.schema.json
|
|
```
|
|
|
|
#### GCP to GCP VPN
|
|
|
|
These examples demonstrates VPC to VPC connectivity via HA VPN.
|
|
In this examples, project `net-land-01` has a VPC named `hub` and project `net-dev-01` has a VPC named `dev-spoke`; the two VPCs are connected together via HA VPN. In order to do so, the `vpc_config.vpn_config.to-hub.peer_gateways.default.gcp` on each side is configured by cross-referencing the VPN gateway in the other side, whose reference is `<project_id>/<vpc_name>/<vpn_name>`.
|
|
|
|
```hcl
|
|
module "net-vpc-factory" {
|
|
source = "./fabric/modules/net-vpc-factory"
|
|
billing_account = "123456-789012-345678"
|
|
parent_id = "folders/123456789012"
|
|
prefix = "myprefix"
|
|
factories_config = { vpcs = "recipes/examples" }
|
|
}
|
|
# tftest files=vpn-hub,vpn-spoke
|
|
```
|
|
|
|
Hub:
|
|
|
|
```yaml
|
|
project_config:
|
|
name: net-land-01
|
|
services:
|
|
- compute.googleapis.com
|
|
vpc_config:
|
|
hub:
|
|
vpn_config:
|
|
to-dev:
|
|
region: europe-west12
|
|
peer_gateways:
|
|
default:
|
|
gcp: net-dev-01/dev-spoke/to-hub
|
|
router_config:
|
|
asn: 64521
|
|
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
|
|
# tftest-file id=vpn-hub path=recipes/examples/net-land-01.yaml schema=network-project.schema.json
|
|
```
|
|
|
|
Dev Spoke:
|
|
|
|
```yaml
|
|
project_config:
|
|
name: net-dev-01
|
|
services:
|
|
- compute.googleapis.com
|
|
vpc_config:
|
|
dev-spoke:
|
|
vpn_config:
|
|
to-hub:
|
|
region: europe-west12
|
|
peer_gateways:
|
|
default:
|
|
gcp: net-land-01/hub/to-dev
|
|
router_config:
|
|
asn: 64520
|
|
tunnels:
|
|
remote-0:
|
|
shared_secret: foobar
|
|
bgp_peer:
|
|
address: 169.254.2.1
|
|
asn: 64521
|
|
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: 64521
|
|
bgp_session_range: "169.254.2.6/30"
|
|
vpn_gateway_interface: 1
|
|
# tftest-file id=vpn-spoke path=recipes/examples/net-dev-01.yaml schema=network-project.schema.json
|
|
```
|
|
|
|
### Network Connectivity Center (NCC)
|
|
|
|
#### NCC VPC Spokes
|
|
|
|
This example demonstrates how to create an NCC hub, and how to connect multiple spokes to it. On the `net-land-01` project, `ncc_hub_config.groups.default.auto_accept` is configured to automatically accept the listed spoke projects.
|
|
On the spokes definition, `vpc_config.$env-spoke.ncc_config` cross references the hub and the default group.
|
|
|
|
NCC Hub:
|
|
|
|
```hcl
|
|
module "net-vpc-factory" {
|
|
source = "./fabric/modules/net-vpc-factory"
|
|
billing_account = "123456-789012-345678"
|
|
parent_id = "folders/123456789012"
|
|
prefix = "myprefix"
|
|
factories_config = { vpcs = "recipes/examples" }
|
|
}
|
|
# tftest files=ncc-hub,ncc-dev,ncc-prod
|
|
```
|
|
|
|
```yaml
|
|
project_config:
|
|
name: net-land-01
|
|
services:
|
|
- compute.googleapis.com
|
|
- networkmanagement.googleapis.com
|
|
ncc_hub_config:
|
|
name: hub
|
|
groups:
|
|
default:
|
|
auto_accept:
|
|
- net-prod-01
|
|
- net-dev-01
|
|
# tftest-file id=ncc-hub path=recipes/examples/net-land-01.yaml schema=network-project.schema.json
|
|
```
|
|
|
|
Dev Spoke:
|
|
|
|
```yaml
|
|
project_config:
|
|
name: net-dev-01
|
|
services:
|
|
- compute.googleapis.com
|
|
- networkmanagement.googleapis.com
|
|
vpc_config:
|
|
dev-spoke:
|
|
ncc_config:
|
|
hub: net-land-01/hub
|
|
# tftest-file id=ncc-dev path=recipes/examples/net-dev-01.yaml schema=network-project.schema.json
|
|
```
|
|
|
|
Prod Spoke:
|
|
|
|
```yaml
|
|
project_config:
|
|
name: net-prod-01
|
|
services:
|
|
- compute.googleapis.com
|
|
- networkmanagement.googleapis.com
|
|
vpc_config:
|
|
prod-spoke:
|
|
ncc_config:
|
|
hub: net-land-01/hub
|
|
group: net-land-01/hub/default
|
|
# tftest-file id=ncc-prod path=recipes/examples/net-prod-01.yaml schema=network-project.schema.json
|
|
```
|
|
|
|
#### NCC VPN Spokes
|
|
|
|
This example shows how to connect HA VPN tunnels, typically used for on-premises or other cloud connections, as spokes in an NCC Hub. This enables transitive routing between VPC spokes and the VPN connection via the NCC Hub.
|
|
|
|
The key is the `ncc_spoke_config` block within the `vpn_config` definition on the hub project (`net-land-01/hub`).
|
|
|
|
```hcl
|
|
module "net-vpc-factory" {
|
|
source = "./fabric/modules/net-vpc-factory"
|
|
billing_account = "123456-789012-345678"
|
|
parent_id = "folders/123456789012"
|
|
prefix = "myprefix"
|
|
factories_config = { vpcs = "recipes/examples" }
|
|
}
|
|
# tftest files=ncc-vpn
|
|
```
|
|
|
|
```yaml
|
|
project_config:
|
|
name: net-land-01
|
|
services:
|
|
- compute.googleapis.com
|
|
- networkmanagement.googleapis.com
|
|
ncc_hub_config:
|
|
name: hub
|
|
vpc_config:
|
|
hub:
|
|
mtu: 1500
|
|
routers:
|
|
vpn-router:
|
|
region: europe-west8
|
|
asn: 64514
|
|
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
|
|
# tftest-file id=ncc-vpn path=recipes/examples/net-land-01.yaml schema=network-project.schema.json
|
|
```
|
|
|
|
## DNS
|
|
|
|
This module supports the creation of forwarding zones, peering zones, public and private zones, and recordsets within these zones. `vpc_config.$vpc.dns_zones` implements a large subset of the [net-dns](../dns/) module variable interface.
|
|
|
|
Below a few configuration examples:
|
|
|
|
### Private Zone
|
|
|
|
This example demonstrates how to create a private zone for the internal.example.com domain, and how to add a record set to it.
|
|
|
|
```hcl
|
|
module "net-vpc-factory" {
|
|
source = "./fabric/modules/net-vpc-factory"
|
|
billing_account = "123456-789012-345678"
|
|
parent_id = "folders/123456789012"
|
|
prefix = "myprefix"
|
|
factories_config = { vpcs = "recipes/examples" }
|
|
}
|
|
# tftest files=dns-private
|
|
```
|
|
|
|
```yaml
|
|
project_config:
|
|
name: net-land-01
|
|
services:
|
|
- compute.googleapis.com
|
|
- dns.googleapis.com
|
|
vpc_config:
|
|
hub:
|
|
dns_zones:
|
|
internal-example:
|
|
zone_config:
|
|
domain: internal.example.com.
|
|
private:
|
|
client_networks:
|
|
- net-land-01/hub
|
|
recordsets:
|
|
"A localhost":
|
|
records: ["127.0.0.1"]
|
|
# tftest-file id=dns-private path=recipes/examples/net-land-01.yaml schema=network-project.schema.json
|
|
```
|
|
|
|
### Forwarding Zone
|
|
|
|
This example demonstrates how to create a forwarding zone that forwards queries for the `example.com` domain to on-premises DNS servers.
|
|
|
|
```hcl
|
|
module "net-vpc-factory" {
|
|
source = "./fabric/modules/net-vpc-factory"
|
|
billing_account = "123456-789012-345678"
|
|
parent_id = "folders/123456789012"
|
|
prefix = "myprefix"
|
|
factories_config = { vpcs = "recipes/examples" }
|
|
}
|
|
# tftest files=dns-fwd
|
|
```
|
|
|
|
```yaml
|
|
project_config:
|
|
name: net-land-01
|
|
services:
|
|
- compute.googleapis.com
|
|
- dns.googleapis.com
|
|
vpc_config:
|
|
hub:
|
|
dns_zones:
|
|
onprem-fwd:
|
|
zone_config:
|
|
domain: example.com.
|
|
forwarding:
|
|
forwarders:
|
|
"10.0.0.1": default
|
|
"10.0.0.2": default
|
|
client_networks:
|
|
- net-land-01/hub
|
|
# tftest-file id=dns-fwd path=recipes/examples/net-land-01.yaml schema=network-project.schema.json
|
|
```
|
|
|
|
### Peering Zone
|
|
|
|
This example demonstrates how to create a peering zone that allows the dev-spoke VPC to resolve names in the net-land-01 project's hub VPC.
|
|
|
|
```hcl
|
|
module "net-vpc-factory" {
|
|
source = "./fabric/modules/net-vpc-factory"
|
|
billing_account = "123456-789012-345678"
|
|
parent_id = "folders/123456789012"
|
|
prefix = "myprefix"
|
|
factories_config = { vpcs = "recipes/examples" }
|
|
}
|
|
# tftest files=dns-peering
|
|
```
|
|
|
|
```yaml
|
|
project_config:
|
|
name: net-dev-01
|
|
services:
|
|
- compute.googleapis.com
|
|
- dns.googleapis.com
|
|
vpc_config:
|
|
dev-spoke:
|
|
dns_zones:
|
|
root-peering:
|
|
zone_config:
|
|
domain: .
|
|
peering:
|
|
peer_network: net-land-01/hub
|
|
client_networks:
|
|
- net-dev-01/dev-spoke
|
|
# tftest-file id=dns-peering path=recipes/examples/net-land-01.yaml schema=network-project.schema.json
|
|
```
|
|
|
|
All of the above combined implements a DNS hub-and-spoke design, where the DNS configuration is mostly centralised in the `net-land-01/hub` VPC, including private zones and forwarding to onprem, and spokes (in this case `net-dev-01/dev-spoke`) "delegate" the root zone (`.`, which is DNS for "*") to the central location via DNS peering.
|
|
|
|
### Public Zone with DNSSEC
|
|
|
|
This example demonstrates creating a public DNS zone and enabling DNSSEC.
|
|
|
|
```hcl
|
|
module "net-vpc-factory" {
|
|
source = "./fabric/modules/net-vpc-factory"
|
|
billing_account = "123456-789012-345678"
|
|
parent_id = "folders/123456789012"
|
|
prefix = "myprefix"
|
|
factories_config = { vpcs = "recipes/examples" }
|
|
}
|
|
# tftest files=dns-public-dnssec
|
|
```
|
|
|
|
```yaml
|
|
project_config:
|
|
name: net-dns-public
|
|
services:
|
|
- compute.googleapis.com
|
|
- dns.googleapis.com
|
|
vpc_config:
|
|
hub:
|
|
dns_zones:
|
|
public-example-com:
|
|
zone_config:
|
|
domain: my-public-domain.example.com.
|
|
public:
|
|
dnssec_config:
|
|
state: "on"
|
|
recordsets:
|
|
"A www":
|
|
records: ["192.0.2.1"]
|
|
# tftest-file id=dns-public-dnssec path=recipes/examples/net-dns-public.yaml schema=network-project.schema.json
|
|
```
|
|
<!-- BEGIN TFDOC -->
|
|
## Variables
|
|
|
|
| name | description | type | required | default |
|
|
|---|---|:---:|:---:|:---:|
|
|
| [billing_account](variables.tf#L17) | Billing account id. | <code>string</code> | ✓ | |
|
|
| [parent_id](variables.tf#L374) | Root node for the projects created by the factory. Must be either organizations/XXXXXXXX or folders/XXXXXXXX. | <code>string</code> | ✓ | |
|
|
| [prefix](variables.tf#L379) | Prefix used for projects. | <code>string</code> | ✓ | |
|
|
| [factories_config](variables.tf#L22) | Configuration for network resource factories. | <code title="object({ vpcs = optional(string, "recipes/hub-and-spoke-ncc") firewall_policy_name = optional(string, "net-default") })">object({…})</code> | | <code title="{ vpcs = "recipes/hub-and-spoke-ncc" }">{…}</code> |
|
|
| [network_project_config](variables.tf#L33) | Consolidated configuration for project, VPCs and their associated resources. | <code title="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({ 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) }) 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) })) }))) }))">map(object({…}))</code> | | <code>null</code> |
|
|
| [project_reuse](variables.tf#L384) | Reuse existing project if not null. If name and number are not passed in, a data source is used. | <code title="object({ use_data_source = optional(bool, true) attributes = optional(object({ name = string number = number services_enabled = optional(list(string), []) })) })">object({…})</code> | | <code>null</code> |
|
|
|
|
## Outputs
|
|
|
|
| name | description | sensitive |
|
|
|---|---|:---:|
|
|
| [host_project_ids](outputs.tf#L17) | Network project ids. | |
|
|
| [host_project_numbers](outputs.tf#L22) | Network project numbers. | |
|
|
| [subnet_ids](outputs.tf#L27) | IDs of subnets created within each VPC. | |
|
|
| [subnet_proxy_only_self_links](outputs.tf#L32) | IDs of proxy-only subnets created within each VPC. | |
|
|
| [subnet_psc_self_links](outputs.tf#L42) | IDs of PSC subnets created within each VPC. | |
|
|
| [vpc_self_links](outputs.tf#L52) | Self-links for the VPCs created on each project. | |
|
|
| [vpn_gateway_endpoints](outputs.tf#L57) | External IP Addresses for the GCP VPN gateways. | |
|
|
<!-- END TFDOC -->
|