This module allows creation and management of VPC networks including subnetworks and subnetwork IAM bindings, and most features and options related to VPCs and subnets.
- Examples
- Simple VPC
- Subnet Options
- Subnet IAM
- Peering
- Shared VPC
- Private Service Networking
- Private Service Networking with peering routes and peered Cloud DNS domains
- Private Service Networking with multiple service providers
- Subnets for Private Service Connect, Proxy-only subnets
- PSC Network Attachments
- DNS Policies
- Subnet Factory
- Custom Routes
- Policy Based Routes
- Private Google Access routes
- Allow Firewall Policy to be evaluated before Firewall Rules
- IPv6
- Variables
- Outputs
module "vpc" {
source = "./fabric/modules/net-vpc"
project_id = var.project_id
name = "my-network"
subnets = [
{
ip_cidr_range = "10.0.0.0/24"
name = "production"
region = "europe-west1"
secondary_ip_ranges = {
pods = "172.16.0.0/20"
services = "192.168.0.0/24"
}
},
{
ip_cidr_range = "10.0.16.0/24"
name = "production"
region = "europe-west2"
}
]
}
# tftest modules=1 resources=5 inventory=simple.yaml e2e
module "vpc" {
source = "./fabric/modules/net-vpc"
project_id = var.project_id
name = "my-network"
subnets = [
# simple subnet
{
name = "simple"
region = "europe-west1"
ip_cidr_range = "10.0.0.0/24"
},
# custom description and PGA disabled
{
name = "no-pga"
region = "europe-west1"
ip_cidr_range = "10.0.1.0/24",
description = "Subnet b"
enable_private_access = false
},
# secondary ranges
{
name = "with-secondary-ranges"
region = "europe-west1"
ip_cidr_range = "10.0.2.0/24"
secondary_ip_ranges = {
a = "192.168.0.0/24"
b = "192.168.1.0/24"
}
},
# enable flow logs
{
name = "with-flow-logs"
region = "europe-west1"
ip_cidr_range = "10.0.3.0/24"
flow_logs_config = {
flow_sampling = 0.5
aggregation_interval = "INTERVAL_10_MIN"
}
}
]
}
# tftest modules=1 resources=7 inventory=subnet-options.yaml e2e
Subnet IAM variables follow our general interface, with extra keys/members for the subnet to which each binding will be applied.
module "vpc" {
source = "./fabric/modules/net-vpc"
project_id = var.project_id
name = "my-network"
subnets = [
{
name = "subnet-1"
region = "europe-west1"
ip_cidr_range = "10.0.1.0/24"
iam = {
"roles/compute.networkUser" = [
"group:${var.group_email}"
]
}
iam_bindings = {
subnet-1-iam = {
members = ["group:${var.group_email}"]
role = "roles/compute.networkUser"
condition = {
expression = "resource.matchTag('123456789012/env', 'prod')"
title = "test_condition"
}
}
}
},
{
name = "subnet-2"
region = "europe-west1"
ip_cidr_range = "10.0.2.0/24"
iam_bindings_additive = {
subnet-2-iam = {
member = "group:${var.group_email}"
role = "roles/compute.networkUser"
subnet = "europe-west1/subnet-2"
}
}
}
]
}
# tftest modules=1 resources=8 inventory=subnet-iam.yaml e2e
A single peering can be configured for the VPC, so as to allow management of simple scenarios, and more complex configurations like hub and spoke by defining the peering configuration on the spoke VPCs. Care must be taken so as a single peering is created/changed/destroyed at a time, due to the specific behaviour of the peering API calls.
If you only want to create the "local" side of the peering, use peering_create_remote_end
to false
. This is useful if you don't have permissions on the remote project/VPC to create peerings.
module "vpc-hub" {
source = "./fabric/modules/net-vpc"
project_id = var.project_id
name = "vpc-hub"
subnets = [{
ip_cidr_range = "10.0.0.0/24"
name = "subnet-1"
region = "europe-west1"
}]
}
module "vpc-spoke-1" {
source = "./fabric/modules/net-vpc"
project_id = var.project_id
name = "vpc-spoke1"
subnets = [{
ip_cidr_range = "10.0.1.0/24"
name = "subnet-2"
region = "europe-west1"
}]
peering_config = {
peer_vpc_self_link = module.vpc-hub.self_link
import_routes = true
}
}
# tftest modules=2 resources=10 inventory=peering.yaml
Shared VPC is a project-level functionality which enables a project to share its VPCs with other projects. The shared_vpc_host
variable is here to help with rapid prototyping, we recommend leveraging the project module for production usage.
module "service-project" {
source = "./fabric/modules/project"
billing_account = var.billing_account_id
name = "prj1"
prefix = var.prefix
parent = var.folder_id
services = [
"cloudresourcemanager.googleapis.com",
"compute.googleapis.com",
"iam.googleapis.com",
"serviceusage.googleapis.com"
]
}
module "vpc-host" {
source = "./fabric/modules/net-vpc"
project_id = var.project_id
name = "my-host-network"
subnets = [
{
ip_cidr_range = "10.0.0.0/24"
name = "subnet-1"
region = "europe-west1"
secondary_ip_ranges = {
pods = "172.16.0.0/20"
services = "192.168.0.0/24"
}
iam = {
"roles/compute.networkUser" = [
"serviceAccount:${var.service_account.email}"
]
"roles/compute.securityAdmin" = [
"serviceAccount:${var.service_account.email}"
]
}
}
]
shared_vpc_host = true
shared_vpc_service_projects = [
module.service-project.project_id
]
}
# tftest modules=2 resources=14 inventory=shared-vpc.yaml e2e
module "vpc" {
source = "./fabric/modules/net-vpc"
project_id = var.project_id
name = "my-network"
subnets = [
{
ip_cidr_range = "10.0.0.0/24"
name = "production"
region = "europe-west1"
}
]
psa_configs = [{
ranges = { myrange = "10.0.1.0/24" }
}]
}
# tftest inventory=psa.yaml e2e
The module prefixes the PSA service to address range names, to disable this behaviour just set the range_prefix
attribute in the PSA configuration:
module "vpc" {
source = "./fabric/modules/net-vpc"
project_id = var.project_id
name = "my-network"
subnets = [
{
ip_cidr_range = "10.0.0.0/24"
name = "production"
region = "europe-west1"
}
]
psa_configs = [{
ranges = { myrange = "10.0.1.0/24" }
range_prefix = ""
}]
}
# tftest inventory=psa-prefix.yaml e2e
Each PSA service can set a different prefix. Ranges will be allocated to the service they are defined in, as in the following example:
module "vpc" {
source = "./fabric/modules/net-vpc"
project_id = var.project_id
name = "my-network"
subnets = [
{
ip_cidr_range = "10.0.0.0/24"
name = "production"
region = "europe-west1"
}
]
psa_configs = [
{
ranges = { myrange = "10.0.1.0/24" }
range_prefix = ""
deletion_policy = "ABANDON"
},
{
ranges = { netapp = "10.0.2.0/24" }
service_producer = "netapp.servicenetworking.goog"
range_prefix = ""
}
]
}
# tftest inventory=psa-prefix-services.yaml e2e
Custom routes can be optionally exported/imported through the peering formed with the Google managed PSA VPC.
module "vpc" {
source = "./fabric/modules/net-vpc"
project_id = var.project_id
name = "my-network"
subnets = [
{
ip_cidr_range = "10.0.0.0/24"
name = "production"
region = "europe-west1"
}
]
psa_configs = [{
ranges = { myrange = "10.0.1.0/24" }
export_routes = true
import_routes = true
peered_domains = ["gcp.example.com."]
}]
}
# tftest modules=1 resources=8 inventory=psa-routes.yaml e2e
module "vpc" {
source = "./fabric/modules/net-vpc"
project_id = var.project_id
name = "my-network"
subnets = [
{
ip_cidr_range = "10.0.0.0/24"
name = "production"
region = "europe-west1"
}
]
psa_configs = [
{
ranges = { myrange = "10.0.1.0/24" }
# service_producer = "servicenetworking.googleapis.com" # default value
deletion_policy = "ABANDON"
},
{
ranges = { netapp = "10.0.2.0/24" }
service_producer = "netapp.servicenetworking.goog"
deletion_policy = "ABANDON"
}
]
}
# tftest modules=1 resources=10 inventory=psa-multiple-providers.yaml e2e
Along with common private subnets module supports creation more service specific subnets for the following purposes:
- Proxy-only subnets for Regional HTTPS Internal HTTPS Load Balancers
- Private Service Connect subnets
module "vpc" {
source = "./fabric/modules/net-vpc"
project_id = var.project_id
name = "my-network"
subnets_proxy_only = [
{
ip_cidr_range = "10.0.1.0/24"
name = "regional-proxy"
region = "europe-west1"
active = true
},
{
ip_cidr_range = "10.0.4.0/24"
name = "global-proxy"
region = "australia-southeast2"
active = true
global = true
}
]
subnets_psc = [
{
ip_cidr_range = "10.0.3.0/24"
name = "psc"
region = "europe-west1"
}
]
}
# tftest modules=1 resources=6 inventory=proxy-only-subnets.yaml e2e
Network attachments are only supported for subnets directly managed by the module. To create network attachments in service projects, refer to the net-address
module documentation.
module "vpc" {
source = "./fabric/modules/net-vpc"
project_id = var.project_id
name = "my-network"
network_attachments = {
prod-ew1 = {
subnet = "europe-west1/production"
producer_accept_lists = [
"my-project-1"
]
}
prod-ew2 = {
subnet = "europe-west2/production"
automatic_connection = true
}
}
subnets = [
{
ip_cidr_range = "10.0.0.0/24"
name = "production"
region = "europe-west1"
},
{
ip_cidr_range = "10.0.16.0/24"
name = "production"
region = "europe-west2"
}
]
}
# tftest modules=1 resources=7 inventory=network-attachments.yaml
module "vpc" {
source = "./fabric/modules/net-vpc"
project_id = var.project_id
name = "my-network"
dns_policy = {
inbound = true
outbound = {
private_ns = ["10.0.0.1"]
public_ns = ["8.8.8.8"]
}
}
subnets = [
{
ip_cidr_range = "10.0.0.0/24"
name = "production"
region = "europe-west1"
}
]
}
# tftest modules=1 resources=5 inventory=dns-policies.yaml e2e
The net-vpc
module includes a subnet factory (see Resource Factories) for the massive creation of subnets leveraging one configuration file per subnet. The factory also supports proxy-only and PSC subnets via the purpose
attribute. The name
attribute is optional and defaults to the file name, allowing to use the same name for subnets in different regions. The context
attribute of var.factories_config
can optionally contain the map regions
, which allows for the templatization of the region
attribute (e.g. see config/subnets/subnet-simple.yaml
below)
module "vpc" {
source = "./fabric/modules/net-vpc"
project_id = var.project_id
name = "my-network"
factories_config = {
subnets_folder = "config/subnets"
context = {
regions = {
primary = "europe-west4"
secondary = "europe-west8"
}
}
}
}
# tftest modules=1 resources=10 files=subnet-simple,subnet-simple-2,subnet-detailed,subnet-proxy,subnet-proxy-global,subnet-psc inventory=factory.yaml
name: simple
region: primary
ip_cidr_range: 10.0.1.0/24
# tftest-file id=subnet-simple path=config/subnets/subnet-simple.yaml schema=subnet.schema.json
name: simple
region: europe-west8
ip_cidr_range: 10.0.2.0/24
# tftest-file id=subnet-simple-2 path=config/subnets/subnet-simple-2.yaml schema=subnet.schema.json
region: europe-west1
description: Sample description
ip_cidr_range: 10.0.0.0/24
# optional attributes
enable_private_access: false # defaults to true
iam:
roles/compute.networkUser:
- group:[email protected]
- serviceAccount:[email protected]
- user:[email protected]
secondary_ip_ranges: # map of secondary ip ranges
secondary-range-a: 192.168.0.0/24
flow_logs_config: # enable, set to empty map to use defaults
aggregation_interval: "INTERVAL_5_SEC"
flow_sampling: 0.5
metadata: "INCLUDE_ALL_METADATA"
# tftest-file id=subnet-detailed path=config/subnets/subnet-detailed.yaml schema=subnet.schema.json
region: europe-west4
ip_cidr_range: 10.1.0.0/24
proxy_only: true
# tftest-file id=subnet-proxy path=config/subnets/subnet-proxy.yaml schema=subnet.schema.json
region: australia-southeast2
ip_cidr_range: 10.4.0.0/24
proxy_only: true
global: true
# tftest-file id=subnet-proxy-global path=config/subnets/subnet-proxy-global.yaml schema=subnet.schema.json
region: europe-west4
ip_cidr_range: 10.2.0.0/24
psc: true
# tftest-file id=subnet-psc path=config/subnets/subnet-psc.yaml schema=subnet.schema.json
VPC routes can be configured through the routes
variable.
locals {
route_types = {
gateway = "global/gateways/default-internet-gateway"
instance = "zones/europe-west1-b/test"
ip = "192.168.0.128"
ilb = "regions/europe-west1/forwardingRules/test"
vpn_tunnel = "regions/europe-west1/vpnTunnels/foo"
}
}
module "vpc" {
source = "./fabric/modules/net-vpc"
for_each = local.route_types
project_id = var.project_id
name = "my-network-with-route-${replace(each.key, "_", "-")}"
routes = {
next-hop = {
description = "Route to internal range."
dest_range = "192.168.128.0/24"
tags = null
next_hop_type = each.key
next_hop = each.value
}
gateway = {
dest_range = "0.0.0.0/0",
priority = 100
tags = ["tag-a"]
next_hop_type = "gateway",
next_hop = "global/gateways/default-internet-gateway"
}
}
create_googleapis_routes = null
}
# tftest modules=5 resources=15 inventory=routes.yaml
Policy based routes can be configured through the policy_based_routes
variable.
module "vpc" {
source = "./fabric/modules/net-vpc"
project_id = var.project_id
name = "my-vpc"
policy_based_routes = {
skip-pbr-for-nva = {
use_default_routing = true
priority = 100
target = {
tags = ["nva"]
}
}
send-all-to-nva = {
next_hop_ilb_ip = "10.0.0.253"
priority = 101
filter = {
src_range = "10.0.0.0/8"
dest_range = "0.0.0.0/0"
}
target = {
interconnect_attachment = "europe-west8"
}
}
}
create_googleapis_routes = null
}
# tftest modules=1 resources=3 inventory=pbr.yaml
By default the VPC module creates IPv4 routes for the Private Google Access ranges. This behavior can be controlled through the create_googleapis_routes
variable:
module "vpc" {
source = "./fabric/modules/net-vpc"
project_id = var.project_id
name = "my-vpc"
create_googleapis_routes = {
restricted = false
restricted-6 = true
private = false
private-6 = true
}
}
# tftest modules=1 resources=3 inventory=googleapis.yaml e2e
module "vpc" {
source = "./fabric/modules/net-vpc"
project_id = var.project_id
name = "my-network"
firewall_policy_enforcement_order = "BEFORE_CLASSIC_FIREWALL"
subnets = [
{
ip_cidr_range = "10.0.0.0/24"
name = "production"
region = "europe-west1"
secondary_ip_ranges = {
pods = "172.16.0.0/20"
services = "192.168.0.0/24"
}
},
{
ip_cidr_range = "10.0.16.0/24"
name = "production"
region = "europe-west2"
}
]
}
# tftest modules=1 resources=5 inventory=firewall_policy_enforcement_order.yaml e2e
A non-overlapping private IPv6 address space can be configured for the VPC via the ipv6_config
variable. If an internal range is not specified, a unique /48 ULA prefix from the fd20::/20
range is assigned.
module "vpc" {
source = "./fabric/modules/net-vpc"
project_id = var.project_id
name = "my-network"
ipv6_config = {
# internal_range is optional
enable_ula_internal = true
# internal_range = "fd20:6b2:27e5::/48"
}
subnets = [
{
ip_cidr_range = "10.0.0.0/24"
name = "test"
region = "europe-west1"
ipv6 = {}
},
{
ip_cidr_range = "10.0.1.0/24"
name = "test"
region = "europe-west3"
ipv6 = {
access_type = "EXTERNAL"
}
}
]
}
# tftest modules=1 resources=5 inventory=ipv6.yaml e2e
name | description | type | required | default |
---|---|---|---|---|
name | The name of the network being created. | string |
✓ | |
project_id | The ID of the project where this VPC will be created. | string |
✓ | |
auto_create_subnetworks | Set to true to create an auto mode subnet, defaults to custom mode. | bool |
false |
|
create_googleapis_routes | Toggle creation of googleapis private/restricted routes. Disabled when vpc creation is turned off, or when set to null. | object({…}) |
{} |
|
delete_default_routes_on_create | Set to true to delete the default routes at creation time. | bool |
false |
|
description | An optional description of this resource (triggers recreation on change). | string |
"Terraform-managed." |
|
dns_policy | DNS policy setup for the VPC. | object({…}) |
null |
|
factories_config | Paths to data files and folders that enable factory functionality. | object({…}) |
{} |
|
firewall_policy_enforcement_order | Order that Firewall Rules and Firewall Policies are evaluated. Can be either 'BEFORE_CLASSIC_FIREWALL' or 'AFTER_CLASSIC_FIREWALL'. | string |
"AFTER_CLASSIC_FIREWALL" |
|
ipv6_config | Optional IPv6 configuration for this network. | object({…}) |
{} |
|
mtu | Maximum Transmission Unit in bytes. The minimum value for this field is 1460 (the default) and the maximum value is 1500 bytes. | number |
null |
|
network_attachments | PSC network attachments, names as keys. | map(object({…})) |
{} |
|
peering_config | VPC peering configuration. | object({…}) |
null |
|
policy_based_routes | Policy based routes, keyed by name. | map(object({…})) |
{} |
|
psa_configs | The Private Service Access configuration. | list(object({…})) |
[] |
|
routes | Network routes, keyed by name. | map(object({…})) |
{} |
|
routing_mode | The network routing mode (default 'GLOBAL'). | string |
"GLOBAL" |
|
shared_vpc_host | Enable shared VPC for this project. | bool |
false |
|
shared_vpc_service_projects | Shared VPC service projects to register with this host. | list(string) |
[] |
|
subnets | Subnet configuration. | list(object({…})) |
[] |
|
subnets_private_nat | List of private NAT subnets. | list(object({…})) |
[] |
|
subnets_proxy_only | List of proxy-only subnets for Regional HTTPS or Internal HTTPS load balancers. Note: Only one proxy-only subnet for each VPC network in each region can be active. | list(object({…})) |
[] |
|
subnets_psc | List of subnets for Private Service Connect service producers. | list(object({…})) |
[] |
|
vpc_create | Create VPC. When set to false, uses a data source to reference existing VPC. | bool |
true |
name | description | sensitive |
---|---|---|
id | Fully qualified network id. | |
internal_ipv6_range | ULA range. | |
name | Network name. | |
network | Network resource. | |
network_attachment_ids | IDs of network attachments. | |
project_id | Project ID containing the network. Use this when you need to create resources after the VPC is fully set up (e.g. subnets created, shared VPC service projects attached, Private Service Networking configured). | |
self_link | Network self link. | |
subnet_ids | Map of subnet IDs keyed by name. | |
subnet_ips | Map of subnet address ranges keyed by name. | |
subnet_ipv6_external_prefixes | Map of subnet external IPv6 prefixes keyed by name. | |
subnet_regions | Map of subnet regions keyed by name. | |
subnet_secondary_ranges | Map of subnet secondary ranges keyed by name. | |
subnet_self_links | Map of subnet self links keyed by name. | |
subnets | Subnet resources. | |
subnets_private_nat | Private NAT subnet resources. | |
subnets_proxy_only | L7 ILB or L7 Regional LB subnet resources. | |
subnets_psc | Private Service Connect subnet resources. |