diff --git a/blueprints/README.md b/blueprints/README.md index 61323dab..60055b18 100644 --- a/blueprints/README.md +++ b/blueprints/README.md @@ -8,7 +8,7 @@ Currently available blueprints: - **data solutions** - [GCE/GCS CMEK via centralized Cloud KMS](./data-solutions/gcs-to-bq-with-least-privileges/), [Cloud Storage to Bigquery with Cloud Dataflow with least privileges](./data-solutions/gcs-to-bq-with-least-privileges/), [Data Platform Foundations](./data-solutions/data-platform-foundations/), [SQL Server AlwaysOn availability groups blueprint](./data-solutions/sqlserver-alwayson), [Cloud SQL instance with multi-region read replicas](./data-solutions/cloudsql-multiregion/), [Cloud Composer version 2 private instance, supporting Shared VPC and external CMEK key](./data-solutions/composer-2/) - **factories** - [The why and the how of resource factories](./factories/README.md) - **GKE** - [GKE multitenant fleet](./gke/multitenant-fleet/), [Shared VPC with GKE support](./networking/shared-vpc-gke/), [Binary Authorization Pipeline](./gke/binauthz/), [Multi-cluster mesh on GKE (fleet API)](./gke/multi-cluster-mesh-gke-fleet-api/) -- **networking** - [hub and spoke via peering](./networking/hub-and-spoke-peering/), [hub and spoke via VPN](./networking/hub-and-spoke-vpn/), [DNS and Google Private Access for on-premises](./networking/onprem-google-access-dns/), [Shared VPC with GKE support](./networking/shared-vpc-gke/), [ILB as next hop](./networking/ilb-next-hop), [PSC for on-premises Cloud Function invocation](./networking/private-cloud-function-from-onprem/), [decentralized firewall](./networking/decentralized-firewall) +- **networking** - [hub and spoke via peering](./networking/hub-and-spoke-peering/), [hub and spoke via VPN](./networking/hub-and-spoke-vpn/), [DNS and Google Private Access for on-premises](./networking/onprem-google-access-dns/), [Shared VPC with GKE support](./networking/shared-vpc-gke/), [ILB as next hop](./networking/ilb-next-hop), [Connecting to on-premise services leveraging PSC and hybrid NEGs](./networking/psc-hybrid/), [decentralized firewall](./networking/decentralized-firewall) - **serverless** - [Multi-region deployments for API Gateway](./serverless/api-gateway/) - **third party solutions** - [OpenShift cluster on Shared VPC](./third-party-solutions/openshift) diff --git a/blueprints/networking/README.md b/blueprints/networking/README.md index b35ec057..981fccc0 100644 --- a/blueprints/networking/README.md +++ b/blueprints/networking/README.md @@ -39,11 +39,18 @@ It is meant to be used as a starting point for most Shared VPC configurations, a This [blueprint](./ilb-next-hop/) allows testing [ILB as next hop](https://cloud.google.com/load-balancing/docs/internal/ilb-next-hop-overview) using simple Linux gateway VMS between two VPCs, to emulate virtual appliances. An optional additional ILB can be enabled to test multiple load balancer configurations and hashing.
-### Calling a private Cloud Function from On-premises +### Calling a private Cloud Function from on-premises This [blueprint](./private-cloud-function-from-onprem/) shows how to invoke a [private Google Cloud Function](https://cloud.google.com/functions/docs/networking/network-settings) from the on-prem environment via a [Private Service Connect endpoint](https://cloud.google.com/vpc/docs/private-service-connect#benefits-apis).
+### Calling on-premise services through PSC and hybrid NEGs + + This [blueprint](./psc-hybrid/) shows how to privately connect to on-premise services (IP + port) from GCP, leveraging [Private Service Connect (PSC)](https://cloud.google.com/vpc/docs/private-service-connect) and [Hybrid Network Endpoint Groups](https://cloud.google.com/load-balancing/docs/negs/hybrid-neg-concepts). +
+ +![High-level diagram](diagram.png "High-level diagram") + ### Decentralized firewall management This [blueprint](./decentralized-firewall/) shows how a decentralized firewall management can be organized using the [firewall factory](../factories/net-vpc-firewall-yaml/). diff --git a/blueprints/networking/psc-hybrid/README.md b/blueprints/networking/psc-hybrid/README.md new file mode 100644 index 00000000..1b67596b --- /dev/null +++ b/blueprints/networking/psc-hybrid/README.md @@ -0,0 +1,55 @@ +# Hybrid connectivity to on-premise services through PSC + +The sample allows to connect to an on-prem service leveraging Private Service Connect (PSC). + +It creates: + +* A [producer](./psc-producer/README.md): a VPC exposing a PSC Service Attachment (SA), connecting to an internal regional TCP proxy load balancer, using a hybrid NEG backend that connects to an on-premises service (IP address + port) + +* A [consumer](./psc-consumer/README.md): a VPC with a PSC endpoint pointing to the PSC SA exposed by the producer. The endpoint is accessible by clients through a local IP address on the consumer VPC. + +![High-level diagram](diagram.png "High-level diagram") + +## Sample modules + +The blueprint makes use of the modules [psc-producer](psc-producer) and [psc-consumer](psc-consumer) contained in this folder. This is done so you can build on top of these building blocks, in order to support more complex scenarios. + +## Prerequisites + +Before applying this Terraform + +- On-premises + - Allow ingress from *35.191.0.0/16* and *130.211.0.0/22* CIDRs (for HCs) + - Allow ingress from the proxy-only subnet CIDR +- GCP + - Advertise from GCP to on-prem *35.191.0.0/16* and *130.211.0.0/22* CIDRs + - Advertise from GCP to on-prem the proxy-only subnet CIDRs + +## Relevant Links + +* [Private Service Connect](https://cloud.google.com/vpc/docs/private-service-connect) + +* [Hybrid connectivity Network Endpoint Groups](https://cloud.google.com/load-balancing/docs/negs/hybrid-neg-concepts) + +* [Regional TCP Proxy with Hybrid NEGs](https://cloud.google.com/load-balancing/docs/tcp/set-up-int-tcp-proxy-hybrid) + +* [PSC approval](https://cloud.google.com/vpc/docs/configure-private-service-connect-producer#publish-service-explicit) + + +## Variables + +| name | description | type | required | default | +|---|---|:---:|:---:|:---:| +| [dest_ip_address](variables.tf#L37) | On-prem service destination IP address. | string | ✓ | | +| [prefix](variables.tf#L17) | Prefix to use for resource names. | string | ✓ | | +| [producer](variables.tf#L88) | Producer configuration. | object({…}) | ✓ | | +| [project_id](variables.tf#L22) | When referncing existing projects, the id of the project where resources will be created. | string | ✓ | | +| [region](variables.tf#L27) | Region where resources will be created. | string | ✓ | | +| [subnet_consumer](variables.tf#L98) | Consumer subnet CIDR. | string # CIDR | ✓ | | +| [zone](variables.tf#L32) | Zone where resources will be created. | string | ✓ | | +| [dest_port](variables.tf#L42) | On-prem service destination port. | string | | "80" | +| [project_create](variables.tf#L48) | Whether to automatically create a project. | bool | | false | +| [vpc_config](variables.tf#L60) | VPC and subnet ids, in case existing VPCs are used. | object({…}) | | {…} | +| [vpc_create](variables.tf#L54) | Whether to automatically create VPCs. | bool | | true | + + diff --git a/blueprints/networking/psc-hybrid/diagram.png b/blueprints/networking/psc-hybrid/diagram.png new file mode 100644 index 00000000..acb36be9 Binary files /dev/null and b/blueprints/networking/psc-hybrid/diagram.png differ diff --git a/blueprints/networking/psc-hybrid/main.tf b/blueprints/networking/psc-hybrid/main.tf new file mode 100644 index 00000000..21d297f0 --- /dev/null +++ b/blueprints/networking/psc-hybrid/main.tf @@ -0,0 +1,136 @@ +/** + * Copyright 2022 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. + */ + +locals { + prefix = coalesce(var.prefix, "") == "" ? "" : "${var.prefix}-" + project_id = ( + var.project_create + ? module.project.project_id + : var.project_id + ) + vpc_producer_id = ( + var.vpc_create + ? module.vpc_producer.network.id + : var.vpc_config["producer"]["id"] + ) + vpc_producer_main = ( + var.vpc_create + ? module.vpc_producer.subnets["${var.region}/${var.prefix}-main"].id + : var.vpc_config["producer"]["subnet_main_id"] + ) + vpc_producer_proxy = ( + var.vpc_create + ? module.vpc_producer.subnets_proxy_only["${var.region}/${var.prefix}-proxy"].id + : var.vpc_config["producer"]["subnet_proxy_id"] + ) + vpc_producer_psc = ( + var.vpc_create + ? module.vpc_producer.subnets_psc["${var.region}/${var.prefix}-psc"].id + : var.vpc_config["producer"]["subnet_psc_id"] + ) + vpc_consumer_id = ( + var.vpc_create + ? module.vpc_consumer.network.id + : var.vpc_config["consumer"]["id"] + ) + vpc_consumer_main = ( + var.vpc_create + ? module.vpc_consumer.subnets["${var.region}/${var.prefix}-consumer"].id + : var.vpc_config["consumer"]["subnet_main_id"] + ) +} + +module "project" { + source = "../../../modules/project" + name = var.project_id + project_create = var.project_create + services = [ + "compute.googleapis.com" + ] +} + +# Producer +module "vpc_producer" { + source = "../../../modules/net-vpc" + project_id = local.project_id + name = "${local.prefix}producer" + subnets = [ + { + ip_cidr_range = var.producer["subnet_main"] + name = "${var.prefix}-main" + region = var.region + secondary_ip_range = {} + } + ] + subnets_proxy_only = [ + { + ip_cidr_range = var.producer["subnet_proxy"] + name = "${local.prefix}proxy" + region = var.region + active = true + } + ] + subnets_psc = [ + { + ip_cidr_range = var.producer["subnet_psc"] + name = "${local.prefix}psc" + region = var.region + } + ] +} + +module "psc_producer" { + source = "./psc-producer" + project_id = local.project_id + name = var.prefix + dest_ip_address = var.dest_ip_address + dest_port = var.dest_port + network = local.vpc_producer_id + region = var.region + zone = var.zone + subnet = local.vpc_producer_main + subnet_proxy = local.vpc_producer_proxy + subnets_psc = [ + local.vpc_producer_psc + ] + accepted_limits = var.producer["accepted_limits"] +} + +# Consumer + +module "vpc_consumer" { + source = "../../../modules/net-vpc" + project_id = local.project_id + name = "${local.prefix}consumer" + subnets = [ + { + ip_cidr_range = var.subnet_consumer + name = "${local.prefix}consumer" + region = var.region + secondary_ip_range = {} + } + ] +} + +module "psc_consumer" { + source = "./psc-consumer" + project_id = local.project_id + name = "${local.prefix}consumer" + region = var.region + network = local.vpc_consumer_id + subnet = local.vpc_consumer_main + sa_id = module.psc_producer.service_attachment.id +} diff --git a/blueprints/networking/psc-hybrid/psc-consumer/README.md b/blueprints/networking/psc-hybrid/psc-consumer/README.md new file mode 100644 index 00000000..919e8aaf --- /dev/null +++ b/blueprints/networking/psc-hybrid/psc-consumer/README.md @@ -0,0 +1,15 @@ +# PSC Consumer + + +## Variables + +| name | description | type | required | default | +|---|---|:---:|:---:|:---:| +| [name](variables.tf#L22) | Name of the resources created. | string | ✓ | | +| [network](variables.tf#L32) | Consumer network id. | string | ✓ | | +| [project_id](variables.tf#L17) | The ID of the project where this VPC will be created. | string | ✓ | | +| [region](variables.tf#L27) | Region where resources will be created. | string | ✓ | | +| [sa_id](variables.tf#L42) | PSC producer service attachment id. | string | ✓ | | +| [subnet](variables.tf#L37) | Subnetwork id where resources will be associated. | string | ✓ | | + + diff --git a/blueprints/networking/psc-hybrid/psc-consumer/main.tf b/blueprints/networking/psc-hybrid/psc-consumer/main.tf new file mode 100644 index 00000000..7967aa7a --- /dev/null +++ b/blueprints/networking/psc-hybrid/psc-consumer/main.tf @@ -0,0 +1,33 @@ +/** + * Copyright 2022 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. + */ + +resource "google_compute_address" "psc_endpoint_address" { + name = var.name + project = var.project_id + address_type = "INTERNAL" + subnetwork = var.subnet + region = var.region +} + +resource "google_compute_forwarding_rule" "psc_ilb_consumer" { + name = var.name + project = var.project_id + region = var.region + target = var.sa_id + load_balancing_scheme = "" + network = var.network + ip_address = google_compute_address.psc_endpoint_address.id +} diff --git a/blueprints/networking/psc-hybrid/psc-consumer/variables.tf b/blueprints/networking/psc-hybrid/psc-consumer/variables.tf new file mode 100644 index 00000000..47a0f9a6 --- /dev/null +++ b/blueprints/networking/psc-hybrid/psc-consumer/variables.tf @@ -0,0 +1,45 @@ +/** + * Copyright 2022 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 "project_id" { + description = "The ID of the project where this VPC will be created." + type = string +} + +variable "name" { + description = "Name of the resources created." + type = string +} + +variable "region" { + description = "Region where resources will be created." + type = string +} + +variable "network" { + description = "Consumer network id." + type = string +} + +variable "subnet" { + description = "Subnetwork id where resources will be associated." + type = string +} + +variable "sa_id" { + description = "PSC producer service attachment id." + type = string +} diff --git a/blueprints/networking/psc-hybrid/psc-producer/README.md b/blueprints/networking/psc-hybrid/psc-producer/README.md new file mode 100644 index 00000000..12e208e5 --- /dev/null +++ b/blueprints/networking/psc-hybrid/psc-producer/README.md @@ -0,0 +1,26 @@ +# PSC Producer + + +## Variables + +| name | description | type | required | default | +|---|---|:---:|:---:|:---:| +| [accepted_limits](variables.tf#L68) | Incoming accepted projects with endpoints limit. | map(number) | ✓ | | +| [dest_ip_address](variables.tf#L57) | On-prem service destination IP address. | string | ✓ | | +| [name](variables.tf#L22) | Name of the resources created. | string | ✓ | | +| [network](variables.tf#L37) | Producer network id. | string | ✓ | | +| [project_id](variables.tf#L17) | The ID of the project where this VPC will be created. | string | ✓ | | +| [region](variables.tf#L27) | Region where resources will be created. | string | ✓ | | +| [subnet](variables.tf#L42) | Subnetwork id where resources will be associated. | string | ✓ | | +| [subnet_proxy](variables.tf#L47) | L7 Regional load balancing subnet id. | string | ✓ | | +| [subnets_psc](variables.tf#L52) | PSC NAT subnets. | list(string) | ✓ | | +| [zone](variables.tf#L32) | Zone where resources will be created. | string | ✓ | | +| [dest_port](variables.tf#L62) | On-prem service destination port. | string | | "80" | + +## Outputs + +| name | description | sensitive | +|---|---|:---:| +| [service_attachment](outputs.tf#L17) | The service attachment resource. | | + + diff --git a/blueprints/networking/psc-hybrid/psc-producer/main.tf b/blueprints/networking/psc-hybrid/psc-producer/main.tf new file mode 100644 index 00000000..01212bad --- /dev/null +++ b/blueprints/networking/psc-hybrid/psc-producer/main.tf @@ -0,0 +1,107 @@ +/** + * Copyright 2022 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. + */ + +# Hybrid NEG + +resource "google_compute_network_endpoint_group" "neg" { + name = var.name + project = var.project_id + network = var.network + default_port = var.dest_port + zone = "${var.region}-${var.zone}" + network_endpoint_type = "NON_GCP_PRIVATE_IP_PORT" +} + +resource "google_compute_network_endpoint" "endpoint" { + project = var.project_id + network_endpoint_group = google_compute_network_endpoint_group.neg.name + port = var.dest_port + ip_address = var.dest_ip_address + zone = "${var.region}-${var.zone}" +} + +# TCP Proxy ILB + +resource "google_compute_region_health_check" "health_check" { + name = var.name + project = var.project_id + region = var.region + timeout_sec = 1 + check_interval_sec = 1 + + tcp_health_check { + port = var.dest_port + } +} + +resource "google_compute_region_backend_service" "backend_service" { + name = var.name + project = var.project_id + region = var.region + health_checks = [google_compute_region_health_check.health_check.id] + load_balancing_scheme = "INTERNAL_MANAGED" + protocol = "TCP" + + backend { + group = google_compute_network_endpoint_group.neg.self_link + balancing_mode = "CONNECTION" + failover = false + capacity_scaler = 1.0 + max_connections = 100 + } +} + +resource "google_compute_region_target_tcp_proxy" "target_proxy" { + provider = google-beta + name = var.name + region = var.region + project = var.project_id + backend_service = google_compute_region_backend_service.backend_service.id +} + +resource "google_compute_forwarding_rule" "forwarding_rule" { + provider = google-beta + name = var.name + project = var.project_id + region = var.region + ip_protocol = "TCP" + load_balancing_scheme = "INTERNAL_MANAGED" + port_range = var.dest_port + target = google_compute_region_target_tcp_proxy.target_proxy.id + network = var.network + subnetwork = var.subnet + network_tier = "PREMIUM" +} + +# PSC Service Attachment + +resource "google_compute_service_attachment" "service_attachment" { + name = var.name + project = var.project_id + region = var.region + enable_proxy_protocol = false + connection_preference = "ACCEPT_MANUAL" + nat_subnets = var.subnets_psc + target_service = google_compute_forwarding_rule.forwarding_rule.id + + dynamic "consumer_accept_lists" { + for_each = var.accepted_limits + content { + project_id_or_num = consumer_accept_lists.key + connection_limit = consumer_accept_lists.value + } + } +} diff --git a/blueprints/networking/psc-hybrid/psc-producer/outputs.tf b/blueprints/networking/psc-hybrid/psc-producer/outputs.tf new file mode 100644 index 00000000..6539bcd7 --- /dev/null +++ b/blueprints/networking/psc-hybrid/psc-producer/outputs.tf @@ -0,0 +1,20 @@ +/** + * Copyright 2022 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 "service_attachment" { + description = "The service attachment resource." + value = google_compute_service_attachment.service_attachment +} diff --git a/blueprints/networking/psc-hybrid/psc-producer/variables.tf b/blueprints/networking/psc-hybrid/psc-producer/variables.tf new file mode 100644 index 00000000..c085ecdc --- /dev/null +++ b/blueprints/networking/psc-hybrid/psc-producer/variables.tf @@ -0,0 +1,71 @@ +/** + * Copyright 2022 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 "project_id" { + description = "The ID of the project where this VPC will be created." + type = string +} + +variable "name" { + description = "Name of the resources created." + type = string +} + +variable "region" { + description = "Region where resources will be created." + type = string +} + +variable "zone" { + description = "Zone where resources will be created." + type = string +} + +variable "network" { + description = "Producer network id." + type = string +} + +variable "subnet" { + description = "Subnetwork id where resources will be associated." + type = string +} + +variable "subnet_proxy" { + description = "L7 Regional load balancing subnet id." + type = string +} + +variable "subnets_psc" { + description = "PSC NAT subnets." + type = list(string) +} + +variable "dest_ip_address" { + description = "On-prem service destination IP address." + type = string +} + +variable "dest_port" { + description = "On-prem service destination port." + type = string + default = "80" +} + +variable "accepted_limits" { + description = "Incoming accepted projects with endpoints limit." + type = map(number) +} diff --git a/blueprints/networking/psc-hybrid/variables.tf b/blueprints/networking/psc-hybrid/variables.tf new file mode 100644 index 00000000..012e26d0 --- /dev/null +++ b/blueprints/networking/psc-hybrid/variables.tf @@ -0,0 +1,101 @@ +/** + * Copyright 2022 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 "prefix" { + description = "Prefix to use for resource names." + type = string +} + +variable "project_id" { + description = "When referncing existing projects, the id of the project where resources will be created." + type = string +} + +variable "region" { + description = "Region where resources will be created." + type = string +} + +variable "zone" { + description = "Zone where resources will be created." + type = string +} + +variable "dest_ip_address" { + description = "On-prem service destination IP address." + type = string +} + +variable "dest_port" { + description = "On-prem service destination port." + type = string + default = "80" +} + +variable "project_create" { + description = "Whether to automatically create a project." + type = bool + default = false +} + +variable "vpc_create" { + description = "Whether to automatically create VPCs." + type = bool + default = true +} + +variable "vpc_config" { + description = "VPC and subnet ids, in case existing VPCs are used." + type = object({ + producer = object({ + id = string + subnet_main_id = string + subnet_proxy_id = string + subnet_psc_id = string + }) + consumer = object({ + id = string + subnet_main_id = string + }) + }) + default = { + producer = { + id = "xxx" + subnet_main_id = "xxx" + subnet_proxy_id = "xxx" + subnet_psc_id = "xxx" + } + consumer = { + id = "xxx" + subnet_main_id = "xxx" + } + } +} + +variable "producer" { + description = "Producer configuration." + type = object({ + subnet_main = string # CIDR + subnet_proxy = string # CIDR + subnet_psc = string # CIDR + accepted_limits = map(number) # Accepted project ids => PSC endpoint limit + }) +} + +variable "subnet_consumer" { + description = "Consumer subnet CIDR." + type = string # CIDR +}