diff --git a/CHANGELOG.md b/CHANGELOG.md
index 61962c3a..f6e78577 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,7 +7,9 @@ All notable changes to this project will be documented in this file.
- SQL Server AlwaysOn availability groups example
- CloudSQ: fixed Terraform change detection when backup is disabled
- Allow multiple CIDR blocks in the ip_range for Apigee Instance
-- Add prefix to project factory SA bindings
+- Add prefix to project factory SA bindings
+- **incompatible change** `subnets_l7ilb` variable is deprecated in the `net-vpc` module, instead `subnets_proxy_only` variable [should be used](https://cloud.google.com/load-balancing/docs/proxy-only-subnets#proxy_only_subnet_create)
+- Add support for [Private Service Connect](https://cloud.google.com/vpc/docs/private-service-connect#psc-subnets) and [Proxy-only](https://cloud.google.com/load-balancing/docs/proxy-only-subnets) subnets to `net-vpc` module
**FAST**
diff --git a/fast/stages/01-resman/organization.tf b/fast/stages/01-resman/organization.tf
index b917b514..6ce4e9ce 100644
--- a/fast/stages/01-resman/organization.tf
+++ b/fast/stages/01-resman/organization.tf
@@ -82,29 +82,29 @@ module "organization" {
)
# sample subset of useful organization policies, edit to suit requirements
policy_boolean = {
- "constraints/cloudfunctions.requireVPCConnector" = true
- "constraints/compute.disableGuestAttributesAccess" = true
- "constraints/compute.disableInternetNetworkEndpointGroup" = true
- "constraints/compute.disableNestedVirtualization" = true
- "constraints/compute.disableSerialPortAccess" = true
- "constraints/compute.requireOsLogin" = true
- "constraints/compute.restrictXpnProjectLienRemoval" = true
- "constraints/compute.skipDefaultNetworkCreation" = true
- "constraints/compute.setNewProjectDefaultToZonalDNSOnly" = true
+ # "constraints/cloudfunctions.requireVPCConnector" = true
+ # "constraints/compute.disableGuestAttributesAccess" = true
+ # "constraints/compute.disableInternetNetworkEndpointGroup" = true
+ # "constraints/compute.disableNestedVirtualization" = true
+ # "constraints/compute.disableSerialPortAccess" = true
+ "constraints/compute.requireOsLogin" = true
+ # "constraints/compute.restrictXpnProjectLienRemoval" = true
+ "constraints/compute.skipDefaultNetworkCreation" = true
+ # "constraints/compute.setNewProjectDefaultToZonalDNSOnly" = true
"constraints/iam.automaticIamGrantsForDefaultServiceAccounts" = true
"constraints/iam.disableServiceAccountKeyCreation" = true
- "constraints/iam.disableServiceAccountKeyUpload" = true
- "constraints/sql.restrictPublicIp" = true
- "constraints/sql.restrictAuthorizedNetworks" = true
- "constraints/storage.uniformBucketLevelAccess" = true
+ # "constraints/iam.disableServiceAccountKeyUpload" = true
+ "constraints/sql.restrictPublicIp" = true
+ "constraints/sql.restrictAuthorizedNetworks" = true
+ "constraints/storage.uniformBucketLevelAccess" = true
}
policy_list = {
- "constraints/cloudfunctions.allowedIngressSettings" = merge(
- local.list_allow, { values = ["is:ALLOW_INTERNAL_ONLY"] }
- )
- "constraints/cloudfunctions.allowedVpcConnectorEgressSettings" = merge(
- local.list_allow, { values = ["is:PRIVATE_RANGES_ONLY"] }
- )
+ # "constraints/cloudfunctions.allowedIngressSettings" = merge(
+ # local.list_allow, { values = ["is:ALLOW_INTERNAL_ONLY"] }
+ # )
+ # "constraints/cloudfunctions.allowedVpcConnectorEgressSettings" = merge(
+ # local.list_allow, { values = ["is:PRIVATE_RANGES_ONLY"] }
+ # )
"constraints/compute.restrictLoadBalancerCreationForTypes" = merge(
local.list_allow, { values = ["in:INTERNAL"] }
)
@@ -119,9 +119,9 @@ module "organization" {
"constraints/run.allowedIngress" = merge(
local.list_allow, { values = ["is:internal"] }
)
- "constraints/run.allowedVPCEgress" = merge(
- local.list_allow, { values = ["is:private-ranges-only"] }
- )
+ # "constraints/run.allowedVPCEgress" = merge(
+ # local.list_allow, { values = ["is:private-ranges-only"] }
+ # )
# "constraints/compute.restrictCloudNATUsage" = local.list_deny
# "constraints/compute.restrictDedicatedInterconnectUsage" = local.list_deny
# "constraints/compute.restrictPartnerInterconnectUsage" = local.list_deny
diff --git a/fast/stages/02-networking-nva/spoke-dev.tf b/fast/stages/02-networking-nva/spoke-dev.tf
index 52c37d81..843d544f 100644
--- a/fast/stages/02-networking-nva/spoke-dev.tf
+++ b/fast/stages/02-networking-nva/spoke-dev.tf
@@ -52,7 +52,7 @@ module "dev-spoke-vpc" {
data_folder = "${var.data_dir}/subnets/dev"
delete_default_routes_on_create = true
psa_config = try(var.psa_ranges.dev, null)
- subnets_l7ilb = local.l7ilb_subnets.dev
+ subnets_proxy_only = local.l7ilb_subnets.dev
# Set explicit routes for googleapis; send everything else to NVAs
routes = {
private-googleapis = {
diff --git a/fast/stages/02-networking-nva/spoke-prod.tf b/fast/stages/02-networking-nva/spoke-prod.tf
index 9996bb76..d0a22dc9 100644
--- a/fast/stages/02-networking-nva/spoke-prod.tf
+++ b/fast/stages/02-networking-nva/spoke-prod.tf
@@ -52,7 +52,7 @@ module "prod-spoke-vpc" {
data_folder = "${var.data_dir}/subnets/prod"
delete_default_routes_on_create = true
psa_config = try(var.psa_ranges.prod, null)
- subnets_l7ilb = local.l7ilb_subnets.prod
+ subnets_proxy_only = local.l7ilb_subnets.prod
# Set explicit routes for googleapis; send everything else to NVAs
routes = {
private-googleapis = {
diff --git a/fast/stages/02-networking-peering/spoke-dev.tf b/fast/stages/02-networking-peering/spoke-dev.tf
index 268f5b70..a6713eaf 100644
--- a/fast/stages/02-networking-peering/spoke-dev.tf
+++ b/fast/stages/02-networking-peering/spoke-dev.tf
@@ -46,13 +46,13 @@ module "dev-spoke-project" {
}
module "dev-spoke-vpc" {
- source = "../../../modules/net-vpc"
- project_id = module.dev-spoke-project.project_id
- name = "dev-spoke-0"
- mtu = 1500
- data_folder = "${var.data_dir}/subnets/dev"
- psa_config = try(var.psa_ranges.dev, null)
- subnets_l7ilb = local.l7ilb_subnets.dev
+ source = "../../../modules/net-vpc"
+ project_id = module.dev-spoke-project.project_id
+ name = "dev-spoke-0"
+ mtu = 1500
+ data_folder = "${var.data_dir}/subnets/dev"
+ psa_config = try(var.psa_ranges.dev, null)
+ subnets_proxy_only = local.l7ilb_subnets.dev
# set explicit routes for googleapis in case the default route is deleted
routes = {
private-googleapis = {
diff --git a/fast/stages/02-networking-peering/spoke-prod.tf b/fast/stages/02-networking-peering/spoke-prod.tf
index cf83d2e1..401a0856 100644
--- a/fast/stages/02-networking-peering/spoke-prod.tf
+++ b/fast/stages/02-networking-peering/spoke-prod.tf
@@ -46,13 +46,13 @@ module "prod-spoke-project" {
}
module "prod-spoke-vpc" {
- source = "../../../modules/net-vpc"
- project_id = module.prod-spoke-project.project_id
- name = "prod-spoke-0"
- mtu = 1500
- data_folder = "${var.data_dir}/subnets/prod"
- psa_config = try(var.psa_ranges.prod, null)
- subnets_l7ilb = local.l7ilb_subnets.prod
+ source = "../../../modules/net-vpc"
+ project_id = module.prod-spoke-project.project_id
+ name = "prod-spoke-0"
+ mtu = 1500
+ data_folder = "${var.data_dir}/subnets/prod"
+ psa_config = try(var.psa_ranges.prod, null)
+ subnets_proxy_only = local.l7ilb_subnets.prod
# set explicit routes for googleapis in case the default route is deleted
routes = {
private-googleapis = {
diff --git a/fast/stages/02-networking-vpn/spoke-dev.tf b/fast/stages/02-networking-vpn/spoke-dev.tf
index 268f5b70..a6713eaf 100644
--- a/fast/stages/02-networking-vpn/spoke-dev.tf
+++ b/fast/stages/02-networking-vpn/spoke-dev.tf
@@ -46,13 +46,13 @@ module "dev-spoke-project" {
}
module "dev-spoke-vpc" {
- source = "../../../modules/net-vpc"
- project_id = module.dev-spoke-project.project_id
- name = "dev-spoke-0"
- mtu = 1500
- data_folder = "${var.data_dir}/subnets/dev"
- psa_config = try(var.psa_ranges.dev, null)
- subnets_l7ilb = local.l7ilb_subnets.dev
+ source = "../../../modules/net-vpc"
+ project_id = module.dev-spoke-project.project_id
+ name = "dev-spoke-0"
+ mtu = 1500
+ data_folder = "${var.data_dir}/subnets/dev"
+ psa_config = try(var.psa_ranges.dev, null)
+ subnets_proxy_only = local.l7ilb_subnets.dev
# set explicit routes for googleapis in case the default route is deleted
routes = {
private-googleapis = {
diff --git a/fast/stages/02-networking-vpn/spoke-prod.tf b/fast/stages/02-networking-vpn/spoke-prod.tf
index cf83d2e1..401a0856 100644
--- a/fast/stages/02-networking-vpn/spoke-prod.tf
+++ b/fast/stages/02-networking-vpn/spoke-prod.tf
@@ -46,13 +46,13 @@ module "prod-spoke-project" {
}
module "prod-spoke-vpc" {
- source = "../../../modules/net-vpc"
- project_id = module.prod-spoke-project.project_id
- name = "prod-spoke-0"
- mtu = 1500
- data_folder = "${var.data_dir}/subnets/prod"
- psa_config = try(var.psa_ranges.prod, null)
- subnets_l7ilb = local.l7ilb_subnets.prod
+ source = "../../../modules/net-vpc"
+ project_id = module.prod-spoke-project.project_id
+ name = "prod-spoke-0"
+ mtu = 1500
+ data_folder = "${var.data_dir}/subnets/prod"
+ psa_config = try(var.psa_ranges.prod, null)
+ subnets_proxy_only = local.l7ilb_subnets.prod
# set explicit routes for googleapis in case the default route is deleted
routes = {
private-googleapis = {
diff --git a/modules/net-vpc/README.md b/modules/net-vpc/README.md
index 4102d92e..0941302b 100644
--- a/modules/net-vpc/README.md
+++ b/modules/net-vpc/README.md
@@ -171,6 +171,38 @@ module "vpc" {
# tftest modules=1 resources=5
```
+### Subnets for Private Service Connect, Proxy-only subnets
+
+Along with common private subnets module supports creation more service specific subnets for the following purposes:
+
+ - [Proxy-only subnets](https://cloud.google.com/load-balancing/docs/proxy-only-subnets) for Regional HTTPS Internal HTTPS Load Balancers
+ - [Private Service Connect](https://cloud.google.com/vpc/docs/private-service-connect#psc-subnets) subnets
+
+```hcl
+module "vpc" {
+ source = "./modules/net-vpc"
+ project_id = "my-project"
+ name = "my-network"
+
+ subnets_proxy_only = [
+ {
+ ip_cidr_range = "10.0.1.0/24"
+ name = "regional-proxy"
+ region = "europe-west1"
+ active = true
+ }
+ ]
+ subnets_psc = [
+ {
+ ip_cidr_range = "10.0.3.0/24"
+ name = "psc"
+ region = "europe-west1"
+ }
+ ]
+}
+# tftest modules=1 resources=3
+```
+
### DNS Policies
```hcl
@@ -257,8 +289,9 @@ flow_logs: # enable, set to empty map to use defaults
| [subnet_flow_logs](variables.tf#L163) | Optional map of boolean to control flow logs (default is disabled), keyed by subnet 'region/name'. | map(bool)
| | {}
|
| [subnet_private_access](variables.tf#L169) | Optional map of boolean to control private Google access (default is enabled), keyed by subnet 'region/name'. | map(bool)
| | {}
|
| [subnets](variables.tf#L175) | List of subnets being created. | list(object({…}))
| | []
|
-| [subnets_l7ilb](variables.tf#L186) | List of subnets for private HTTPS load balancer. | list(object({…}))
| | []
|
-| [vpc_create](variables.tf#L197) | Create VPC. When set to false, uses a data source to reference existing VPC. | bool
| | true
|
+| [subnets_proxy_only](variables.tf#L186) | List of proxy-only subnets for Regional HTTPS or Internal HTTPS load balancers. Note: Only one proxy-only subnet for each VPC network in each region can be active. | list(object({…}))
| | []
|
+| [subnets_psc](variables.tf#L197) | List of subnets for Private Service Connect service producers. | list(object({…}))
| | []
|
+| [vpc_create](variables.tf#L207) | Create VPC. When set to false, uses a data source to reference existing VPC. | bool
| | true
|
## Outputs
@@ -274,7 +307,8 @@ flow_logs: # enable, set to empty map to use defaults
| [subnet_secondary_ranges](outputs.tf#L85) | Map of subnet secondary ranges keyed by name. | |
| [subnet_self_links](outputs.tf#L96) | Map of subnet self links keyed by name. | |
| [subnets](outputs.tf#L102) | Subnet resources. | |
-| [subnets_l7ilb](outputs.tf#L107) | L7 ILB subnet resources. | |
+| [subnets_proxy_only](outputs.tf#L107) | L7 ILB or L7 Regional LB subnet resources. | |
+| [subnets_psc](outputs.tf#L112) | Private Service Connect subnet resources. | |
The key format is `subnet_region/subnet_name`. For example `europe-west1/my_subnet`.
diff --git a/modules/net-vpc/outputs.tf b/modules/net-vpc/outputs.tf
index d1e68c34..fd79de65 100644
--- a/modules/net-vpc/outputs.tf
+++ b/modules/net-vpc/outputs.tf
@@ -104,7 +104,12 @@ output "subnets" {
value = { for k, v in google_compute_subnetwork.subnetwork : k => v }
}
-output "subnets_l7ilb" {
- description = "L7 ILB subnet resources."
- value = { for k, v in google_compute_subnetwork.l7ilb : k => v }
+output "subnets_proxy_only" {
+ description = "L7 ILB or L7 Regional LB subnet resources."
+ value = { for k, v in google_compute_subnetwork.proxy_only : k => v }
+}
+
+output "subnets_psc" {
+ description = "Private Service Connect subnet resources."
+ value = { for k, v in google_compute_subnetwork.psc : k => v }
}
diff --git a/modules/net-vpc/subnets.tf b/modules/net-vpc/subnets.tf
index 05ad0aa3..1cc892a0 100644
--- a/modules/net-vpc/subnets.tf
+++ b/modules/net-vpc/subnets.tf
@@ -85,8 +85,12 @@ locals {
{ for subnet in var.subnets : "${subnet.region}/${subnet.name}" => subnet },
local._factory_subnets
)
- subnets_l7ilb = {
- for subnet in var.subnets_l7ilb :
+ subnets_proxy_only = {
+ for subnet in var.subnets_proxy_only :
+ "${subnet.region}/${subnet.name}" => subnet
+ }
+ subnets_psc = {
+ for subnet in var.subnets_psc :
"${subnet.region}/${subnet.name}" => subnet
}
}
@@ -123,22 +127,36 @@ resource "google_compute_subnetwork" "subnetwork" {
}
}
-resource "google_compute_subnetwork" "l7ilb" {
- provider = google-beta
- for_each = local.subnets_l7ilb
+resource "google_compute_subnetwork" "proxy_only" {
+ for_each = local.subnets_proxy_only
project = var.project_id
network = local.network.name
region = each.value.region
name = each.value.name
ip_cidr_range = each.value.ip_cidr_range
- purpose = "INTERNAL_HTTPS_LOAD_BALANCER"
+ purpose = "REGIONAL_MANAGED_PROXY"
role = (
each.value.active || each.value.active == null ? "ACTIVE" : "BACKUP"
)
description = lookup(
local.subnet_descriptions,
"${each.value.region}/${each.value.name}",
- "Terraform-managed."
+ "Terraform-managed proxy-only subnet for Regional HTTPS or Internal HTTPS LB."
+ )
+}
+
+resource "google_compute_subnetwork" "psc" {
+ for_each = local.subnets_psc
+ project = var.project_id
+ network = local.network.name
+ region = each.value.region
+ name = each.value.name
+ ip_cidr_range = each.value.ip_cidr_range
+ purpose = "PRIVATE_SERVICE_CONNECT"
+ description = lookup(
+ local.subnet_descriptions,
+ "${each.value.region}/${each.value.name}",
+ "Terraform-managed subnet for Private Service Connect (PSC NAT)."
)
}
diff --git a/modules/net-vpc/variables.tf b/modules/net-vpc/variables.tf
index 464ccfa0..16b40eec 100644
--- a/modules/net-vpc/variables.tf
+++ b/modules/net-vpc/variables.tf
@@ -183,8 +183,8 @@ variable "subnets" {
default = []
}
-variable "subnets_l7ilb" {
- description = "List of subnets for private HTTPS load balancer."
+variable "subnets_proxy_only" {
+ description = "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."
type = list(object({
active = bool
name = string
@@ -194,6 +194,16 @@ variable "subnets_l7ilb" {
default = []
}
+variable "subnets_psc" {
+ description = "List of subnets for Private Service Connect service producers."
+ type = list(object({
+ name = string
+ ip_cidr_range = string
+ region = string
+ }))
+ default = []
+}
+
variable "vpc_create" {
description = "Create VPC. When set to false, uses a data source to reference existing VPC."
type = bool
diff --git a/modules/project/service-accounts.tf b/modules/project/service-accounts.tf
index 5ba40fc4..f32e187e 100644
--- a/modules/project/service-accounts.tf
+++ b/modules/project/service-accounts.tf
@@ -39,12 +39,13 @@ locals {
dataproc = "service-%s@dataproc-accounts"
gae-flex = "service-%s@gae-api-prod"
# TODO: deprecate gcf
- gcf = "service-%s@gcf-admin-robot"
- pubsub = "service-%s@gcp-sa-pubsub"
- secretmanager = "service-%s@gcp-sa-secretmanager"
- sql = "service-%s@gcp-sa-cloud-sql"
- storage = "service-%s@gs-project-accounts"
- sqladmin = "service-%s@gcp-sa-cloud-sql"
+ gcf = "service-%s@gcf-admin-robot"
+ monitoring-notifications = "service-%s@gcp-sa-monitoring-notification"
+ pubsub = "service-%s@gcp-sa-pubsub"
+ secretmanager = "service-%s@gcp-sa-secretmanager"
+ sql = "service-%s@gcp-sa-cloud-sql"
+ sqladmin = "service-%s@gcp-sa-cloud-sql"
+ storage = "service-%s@gs-project-accounts"
}
service_accounts_default = {
compute = "${local.project.number}-compute@developer.gserviceaccount.com"