diff --git a/build/int.cloudbuild.yaml b/build/int.cloudbuild.yaml index 37f90561..d3b0f7b8 100644 --- a/build/int.cloudbuild.yaml +++ b/build/int.cloudbuild.yaml @@ -127,6 +127,22 @@ steps: - verify lb-http-separate-frontend-and-backend name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS' args: ['/bin/bash', '-c', 'cft test run TestSeparateFrontendAndBackend --stage teardown --verbose'] + # Internal cross regional http load balancer with cloud-run +- id: apply internal-lb-http + waitFor: + - create + name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS' + args: ['/bin/bash', '-c', 'cft test run TestInternalLbCloudRun --stage apply --verbose'] +- id: verify internal-lb-http + waitFor: + - apply internal-lb-http + name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS' + args: ['/bin/bash', '-c', 'sleep 360 && cft test run TestInternalLbCloudRun --stage verify --verbose'] +- id: teardown internal-lb-http + waitFor: + - verify internal-lb-http + name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS' + args: ['/bin/bash', '-c', 'cft test run TestInternalLbCloudRun --stage teardown --verbose'] tags: - 'ci' - 'integration' diff --git a/examples/internal-lb-cloud-run/main.tf b/examples/internal-lb-cloud-run/main.tf new file mode 100644 index 00000000..4a84ac81 --- /dev/null +++ b/examples/internal-lb-cloud-run/main.tf @@ -0,0 +1,175 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +provider "google" { + project = var.project_id +} + +provider "google-beta" { + project = var.project_id +} + +module "internal-lb-network" { + source = "terraform-google-modules/network/google//modules/vpc" + version = "~> 10.0.0" + project_id = var.project_id + network_name = "int-lb-network" + auto_create_subnetworks = false +} + +module "internal-lb-subnet" { + source = "terraform-google-modules/network/google//modules/subnets" + version = "~> 10.0.0" + + subnets = [ + { + subnet_name = "int-lb-subnet-a" + subnet_ip = "10.1.2.0/24" + subnet_region = "us-east1" + }, + { + subnet_name = "int-lb-proxy-only-subnet-a" + subnet_ip = "10.129.0.0/23" + subnet_region = "us-east1" + purpose = "GLOBAL_MANAGED_PROXY" + role = "ACTIVE" + }, + { + subnet_name = "int-lb-subnet-b" + subnet_ip = "10.1.3.0/24" + subnet_region = "us-south1" + }, + { + subnet_name = "int-lb-proxy-only-subnet-b", + subnet_ip = "10.130.0.0/23" + subnet_region = "us-south1" + purpose = "GLOBAL_MANAGED_PROXY" + role = "ACTIVE" + } + ] + + network_name = module.internal-lb-network.network_name + project_id = var.project_id + depends_on = [module.internal-lb-network] +} + +module "backend-service-region-a" { + source = "GoogleCloudPlatform/cloud-run/google//modules/v2" + version = "~> 0.16.3" + project_id = var.project_id + location = "us-central1" + service_name = "bs-a" + containers = [{ "container_name" = "", "container_image" = "gcr.io/cloudrun/hello" }] + members = ["allUsers"] + ingress = "INGRESS_TRAFFIC_INTERNAL_ONLY" + cloud_run_deletion_protection = false + enable_prometheus_sidecar = false +} + +module "backend-service-region-b" { + source = "GoogleCloudPlatform/cloud-run/google//modules/v2" + version = "~> 0.16.3" + project_id = var.project_id + location = "us-west1" + service_name = "bs-b" + containers = [{ "container_name" = "", "container_image" = "gcr.io/cloudrun/hello" }] + members = ["allUsers"] + ingress = "INGRESS_TRAFFIC_INTERNAL_ONLY" + cloud_run_deletion_protection = false + enable_prometheus_sidecar = false +} + +module "internal-lb-http-backend" { + source = "terraform-google-modules/lb-http/google//modules/backend" + version = "~> 12.0" + + project_id = var.project_id + name = "int-lb-http-backend" + enable_cdn = false + load_balancing_scheme = "INTERNAL_MANAGED" + locality_lb_policy = "RANDOM" + serverless_neg_backends = [ + { region : "us-central1", type : "cloud-run", service_name : module.backend-service-region-a.service_name }, + { region : "us-west1", type : "cloud-run", service_name : module.backend-service-region-b.service_name } + ] +} + +module "internal-lb-http-frontend" { + source = "terraform-google-modules/lb-http/google//modules/frontend" + version = "~> 12.0" + + project_id = var.project_id + name = "int-lb-http-frontend" + url_map_input = module.internal-lb-http-backend.backend_service_info + network = module.internal-lb-network.network_name + load_balancing_scheme = "INTERNAL_MANAGED" + internal_forwarding_rules_config = [ + { + "region" : "us-east1", + "subnetwork" : module.internal-lb-subnet.subnets["us-east1/int-lb-subnet-a"].id + }, + { + "region" : "us-south1", + "subnetwork" : module.internal-lb-subnet.subnets["us-south1/int-lb-subnet-b"].id + } + ] +} + +resource "google_vpc_access_connector" "internal_lb_vpc_connector" { + provider = google-beta + project = var.project_id + name = "int-lb-vpc-connector" + region = "us-east1" + ip_cidr_range = "10.8.0.0/28" + network = module.internal-lb-network.network_name + max_throughput = 500 + min_throughput = 300 +} + +module "frontend-service-a" { + source = "GoogleCloudPlatform/cloud-run/google//modules/v2" + version = "~> 0.16.3" + project_id = var.project_id + location = "us-east1" + service_name = "fs-a" + containers = [{ "env_vars" : { "TARGET_IP" : module.internal-lb-http-frontend.ip_address_internal_managed_http[0] }, "ports" = { "container_port" = 80, "name" = "http1" }, "container_name" = "", "container_image" = "gcr.io/design-center-container-repo/redirect-traffic:latest-2002" }] + members = ["allUsers"] + vpc_access = { + connector = google_vpc_access_connector.internal_lb_vpc_connector.id + egress = "ALL_TRAFFIC" + } + ingress = "INGRESS_TRAFFIC_ALL" + cloud_run_deletion_protection = false + enable_prometheus_sidecar = false + depends_on = [google_vpc_access_connector.internal_lb_vpc_connector] +} + +module "frontend-service-b" { + source = "GoogleCloudPlatform/cloud-run/google//modules/v2" + version = "~> 0.16.3" + project_id = var.project_id + location = "us-east1" + service_name = "fs-b" + containers = [{ "env_vars" : { "TARGET_IP" : module.internal-lb-http-frontend.ip_address_internal_managed_http[1] }, "ports" = { "container_port" = 80, "name" = "http1" }, "container_name" = "", "container_image" = "gcr.io/design-center-container-repo/redirect-traffic:latest-2002" }] + members = ["allUsers"] + vpc_access = { + connector = google_vpc_access_connector.internal_lb_vpc_connector.id + egress = "ALL_TRAFFIC" + } + ingress = "INGRESS_TRAFFIC_ALL" + cloud_run_deletion_protection = false + enable_prometheus_sidecar = false +} diff --git a/examples/internal-lb-cloud-run/outputs.tf b/examples/internal-lb-cloud-run/outputs.tf new file mode 100644 index 00000000..22772df2 --- /dev/null +++ b/examples/internal-lb-cloud-run/outputs.tf @@ -0,0 +1,20 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +output "external_cloudrun_uris" { + description = "List of URIs for the frontend Cloud Run services" + value = [module.frontend-service-a.service_uri, module.frontend-service-b.service_uri] +} diff --git a/examples/internal-lb-cloud-run/readme.md b/examples/internal-lb-cloud-run/readme.md new file mode 100644 index 00000000..444c6e16 --- /dev/null +++ b/examples/internal-lb-cloud-run/readme.md @@ -0,0 +1,20 @@ +# HTTP Internal Regional Load Balancer Example + +This example creates a simple application with below components. + +* *Frontend Service*: Two cloud-run services to send request to internal cross-regional load balancers. The cloud-run service uses VPC access connector to send the request to the internal load balancer. +* *Internal Load Balancer*: An internal cross-regional load balancer to distribute traffic to internal cloud run services. +* *Backend Service*: Two cloud-run services to run the actual application code. These can be accessed within internal traffic. The internal Application Load Balancer is considered internal traffic. + + +The `google_compute_backend_service` and its dependencies are created as part of `backend` module. +The forwarding rules and its dependecies are created as part of `frontend` module. + + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| project\_id | n/a | `string` | n/a | yes | + + diff --git a/examples/internal-lb-cloud-run/variables.tf b/examples/internal-lb-cloud-run/variables.tf new file mode 100644 index 00000000..419e3a19 --- /dev/null +++ b/examples/internal-lb-cloud-run/variables.tf @@ -0,0 +1,19 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +variable "project_id" { + type = string +} diff --git a/metadata.yaml b/metadata.yaml index 99297dcd..72db8795 100644 --- a/metadata.yaml +++ b/metadata.yaml @@ -58,6 +58,8 @@ spec: location: examples/https-gke - name: https-redirect location: examples/https-redirect + - name: internal-lb-cloud-run + location: examples/internal-lb-cloud-run - name: lb-http-separate-frontend-and-backend location: examples/lb-http-separate-frontend-and-backend - name: mig-nat-http-lb @@ -338,6 +340,8 @@ spec: - roles/run.admin - roles/iam.serviceAccountUser - roles/certificatemanager.owner + - roles/vpcaccess.admin + - roles/iam.serviceAccountAdmin services: - cloudresourcemanager.googleapis.com - storage-api.googleapis.com @@ -346,6 +350,7 @@ spec: - run.googleapis.com - iam.googleapis.com - certificatemanager.googleapis.com + - vpcaccess.googleapis.com providerVersions: - source: hashicorp/google version: ">= 6.0, < 7" diff --git a/modules/backend/README.md b/modules/backend/README.md index 0bc78add..5c5616c7 100644 --- a/modules/backend/README.md +++ b/modules/backend/README.md @@ -21,7 +21,7 @@ This module creates `google_compute_backend_service` resource and its dependenci | health\_check | Input for creating HttpHealthCheck or HttpsHealthCheck resource for health checking this BackendService. A health check must be specified unless the backend service uses an internet or serverless NEG as a backend. |
object({
host = optional(string, null)
request_path = optional(string, null)
request = optional(string, null)
response = optional(string, null)
port = optional(number, null)
port_name = optional(string, null)
proxy_header = optional(string, null)
port_specification = optional(string, null)
protocol = optional(string, null)
check_interval_sec = optional(number, 5)
timeout_sec = optional(number, 5)
healthy_threshold = optional(number, 2)
unhealthy_threshold = optional(number, 2)
logging = optional(bool, false)
}) | `null` | no |
| host\_path\_mappings | The list of host/path for which traffic could be sent to the backend service | list(object({
host = string
path = string
})) | [| no | | iap\_config | Settings for enabling Cloud Identity Aware Proxy Structure. |
{
"host": "*",
"path": "/*"
}
]
object({
enable = bool
oauth2_client_id = optional(string)
oauth2_client_secret = optional(string)
}) | {
"enable": false
} | no |
-| load\_balancing\_scheme | Load balancing scheme type (EXTERNAL for classic external load balancer, EXTERNAL\_MANAGED for Envoy-based load balancer, and INTERNAL\_SELF\_MANAGED for traffic director). | `string` | `"EXTERNAL_MANAGED"` | no |
+| load\_balancing\_scheme | Load balancing scheme type (EXTERNAL for classic external load balancer, EXTERNAL\_MANAGED for Envoy-based load balancer, INTERNAL\_MANAGED for internal load balancer and INTERNAL\_SELF\_MANAGED for traffic director) | `string` | `"EXTERNAL_MANAGED"` | no |
| locality\_lb\_policy | The load balancing algorithm used within the scope of the locality. | `string` | `null` | no |
| log\_config | This field denotes the logging options for the load balancer traffic served by this backend service. If logging is enabled, logs will be exported to Stackdriver. | object({
enable = bool
sample_rate = number
}) | {
"enable": true,
"sample_rate": 1
} | no |
| name | Name for the backend service. | `string` | n/a | yes |
diff --git a/modules/backend/main.tf b/modules/backend/main.tf
index 0212a7ee..09864b33 100644
--- a/modules/backend/main.tf
+++ b/modules/backend/main.tf
@@ -28,7 +28,7 @@ resource "google_compute_backend_service" "default" {
description = var.description
connection_draining_timeout_sec = var.connection_draining_timeout_sec
enable_cdn = var.enable_cdn
- compression_mode = var.compression_mode
+ compression_mode = var.load_balancing_scheme == "INTERNAL_SELF_MANAGED" || var.load_balancing_scheme == "INTERNAL_MANAGED" ? null : var.compression_mode
custom_request_headers = var.custom_request_headers
custom_response_headers = var.custom_response_headers
session_affinity = var.session_affinity
diff --git a/modules/backend/metadata.display.yaml b/modules/backend/metadata.display.yaml
index 6a406b2c..77480ec8 100644
--- a/modules/backend/metadata.display.yaml
+++ b/modules/backend/metadata.display.yaml
@@ -77,6 +77,11 @@ spec:
load_balancing_scheme:
name: load_balancing_scheme
title: Load Balancing Scheme
+ enumValueLabels:
+ - label: EXTERNAL_MANAGED
+ value: EXTERNAL_MANAGED
+ - label: INTERNAL_MANAGED
+ value: INTERNAL_MANAGED
locality_lb_policy:
name: locality_lb_policy
title: Locality Lb Policy
diff --git a/modules/backend/metadata.yaml b/modules/backend/metadata.yaml
index 814a3bf0..77dd99a9 100644
--- a/modules/backend/metadata.yaml
+++ b/modules/backend/metadata.yaml
@@ -50,6 +50,8 @@ spec:
location: examples/https-gke
- name: https-redirect
location: examples/https-redirect
+ - name: internal-lb-cloud-run
+ location: examples/internal-lb-cloud-run
- name: lb-http-separate-frontend-and-backend
location: examples/lb-http-separate-frontend-and-backend
- name: mig-nat-http-lb
@@ -77,7 +79,7 @@ spec:
varType: string
required: true
- name: load_balancing_scheme
- description: Load balancing scheme type (EXTERNAL for classic external load balancer, EXTERNAL_MANAGED for Envoy-based load balancer, and INTERNAL_SELF_MANAGED for traffic director).
+ description: Load balancing scheme type (EXTERNAL for classic external load balancer, EXTERNAL_MANAGED for Envoy-based load balancer, INTERNAL_MANAGED for internal load balancer and INTERNAL_SELF_MANAGED for traffic director)
varType: string
defaultValue: EXTERNAL_MANAGED
- name: protocol
@@ -305,6 +307,8 @@ spec:
- roles/run.admin
- roles/iam.serviceAccountUser
- roles/certificatemanager.owner
+ - roles/vpcaccess.admin
+ - roles/iam.serviceAccountAdmin
services:
- cloudresourcemanager.googleapis.com
- storage-api.googleapis.com
@@ -313,6 +317,7 @@ spec:
- run.googleapis.com
- iam.googleapis.com
- certificatemanager.googleapis.com
+ - vpcaccess.googleapis.com
providerVersions:
- source: hashicorp/google
version: ">= 6.0, < 7"
diff --git a/modules/backend/variables.tf b/modules/backend/variables.tf
index 28166182..882aff6d 100644
--- a/modules/backend/variables.tf
+++ b/modules/backend/variables.tf
@@ -26,7 +26,7 @@ variable "project_id" {
}
variable "load_balancing_scheme" {
- description = "Load balancing scheme type (EXTERNAL for classic external load balancer, EXTERNAL_MANAGED for Envoy-based load balancer, and INTERNAL_SELF_MANAGED for traffic director)."
+ description = "Load balancing scheme type (EXTERNAL for classic external load balancer, EXTERNAL_MANAGED for Envoy-based load balancer, INTERNAL_MANAGED for internal load balancer and INTERNAL_SELF_MANAGED for traffic director)"
type = string
default = "EXTERNAL_MANAGED"
}
diff --git a/modules/dynamic_backends/metadata.yaml b/modules/dynamic_backends/metadata.yaml
index cad75afd..af4894f7 100644
--- a/modules/dynamic_backends/metadata.yaml
+++ b/modules/dynamic_backends/metadata.yaml
@@ -50,6 +50,8 @@ spec:
location: examples/https-gke
- name: https-redirect
location: examples/https-redirect
+ - name: internal-lb-cloud-run
+ location: examples/internal-lb-cloud-run
- name: lb-http-separate-frontend-and-backend
location: examples/lb-http-separate-frontend-and-backend
- name: mig-nat-http-lb
@@ -330,6 +332,8 @@ spec:
- roles/run.admin
- roles/iam.serviceAccountUser
- roles/certificatemanager.owner
+ - roles/vpcaccess.admin
+ - roles/iam.serviceAccountAdmin
services:
- cloudresourcemanager.googleapis.com
- storage-api.googleapis.com
@@ -338,6 +342,7 @@ spec:
- run.googleapis.com
- iam.googleapis.com
- certificatemanager.googleapis.com
+ - vpcaccess.googleapis.com
providerVersions:
- source: hashicorp/google
version: ">= 6.0, < 7"
diff --git a/modules/frontend/README.md b/modules/frontend/README.md
index 0e43a1dd..e2552a99 100644
--- a/modules/frontend/README.md
+++ b/modules/frontend/README.md
@@ -19,12 +19,13 @@ This module creates `HTTP(S) forwarding rule` and its dependencies. This modules
| http\_port | The port for the HTTP load balancer | `number` | `80` | no |
| https\_port | The port for the HTTPS load balancer | `number` | `443` | no |
| https\_redirect | Set to `true` to enable https redirect on the lb. | `bool` | `false` | no |
+| internal\_forwarding\_rules\_config | List of internal managed forwarding rules config. One of 'address' or 'subnetwork' is required for each. It is only applicable for internal load balancer | list(object({
region = string
address = optional(string)
subnetwork = optional(string)
})) | `[]` | no |
| ipv6\_address | An existing IPv6 address to use (the actual IP address value) | `string` | `null` | no |
| labels | The labels to attach to resources created by this module | `map(string)` | `{}` | no |
-| load\_balancing\_scheme | Load balancing scheme type (EXTERNAL for classic external load balancer, EXTERNAL\_MANAGED for Envoy-based load balancer, and INTERNAL\_SELF\_MANAGED for traffic director) | `string` | `"EXTERNAL_MANAGED"` | no |
+| load\_balancing\_scheme | Load balancing scheme type (EXTERNAL for classic external load balancer, EXTERNAL\_MANAGED for Envoy-based load balancer, INTERNAL\_MANAGED for internal load balancer and INTERNAL\_SELF\_MANAGED for traffic director) | `string` | `"EXTERNAL_MANAGED"` | no |
| managed\_ssl\_certificate\_domains | Create Google-managed SSL certificates for specified domains. Requires `ssl` to be set to `true` | `list(string)` | `[]` | no |
| name | Name for the forwarding rule and prefix for supporting resources | `string` | n/a | yes |
-| network | Network for INTERNAL\_SELF\_MANAGED load balancing scheme | `string` | `"default"` | no |
+| network | Network for internal load balancer | `string` | `"default"` | no |
| private\_key | Content of the private SSL key. Requires `ssl` to be set to `true` and `create_ssl_certificate` set to `true` | `string` | `null` | no |
| project\_id | The project to deploy to, if not set the default provider project is used. | `string` | n/a | yes |
| quic | Specifies the QUIC override policy for this resource. Set true to enable HTTP/3 and Google QUIC support, false to disable both. Defaults to null which enables support for HTTP/3 only. | `bool` | `null` | no |
@@ -44,6 +45,8 @@ This module creates `HTTP(S) forwarding rule` and its dependencies. This modules
| external\_ipv6\_address | The external IPv6 assigned to the global fowarding rule. |
| http\_proxy | The HTTP proxy used by this module. |
| https\_proxy | The HTTPS proxy used by this module. |
+| ip\_address\_internal\_managed\_http | The internal/external IP addresses assigned to the HTTP forwarding rules. |
+| ip\_address\_internal\_managed\_https | The internal/external IP addresses assigned to the HTTPS forwarding rules. |
| ipv6\_enabled | Whether IPv6 configuration is enabled on this load-balancer |
| ssl\_certificate\_created | The SSL certificate create from key/pem |
| url\_map | The default URL map used by this module. |
diff --git a/modules/frontend/main.tf b/modules/frontend/main.tf
index 366ce6af..de2983b7 100644
--- a/modules/frontend/main.tf
+++ b/modules/frontend/main.tf
@@ -23,8 +23,9 @@ locals {
create_http_forward = var.http_forward || var.https_redirect
- is_internal = var.load_balancing_scheme == "INTERNAL_SELF_MANAGED"
- internal_network = local.is_internal ? var.network : null
+ is_internal_self_managed = var.load_balancing_scheme == "INTERNAL_SELF_MANAGED"
+ is_internal_managed = var.load_balancing_scheme == "INTERNAL_MANAGED"
+ internal_network = local.is_internal_self_managed || local.is_internal_managed ? var.network : null
# Create a map with hosts as keys and empty lists as initial values
hosts = toset([for service in var.url_map_input : service.host])
@@ -46,7 +47,7 @@ locals {
resource "google_compute_global_forwarding_rule" "http" {
provider = google-beta
project = var.project_id
- count = local.create_http_forward ? 1 : 0
+ count = local.create_http_forward && !local.is_internal_managed ? 1 : 0
name = var.name
target = google_compute_target_http_proxy.default[0].self_link
ip_address = local.address
@@ -56,10 +57,27 @@ resource "google_compute_global_forwarding_rule" "http" {
network = local.internal_network
}
+resource "google_compute_global_forwarding_rule" "internal_managed_http" {
+ for_each = local.create_http_forward && local.is_internal_managed ? {
+ for config in var.internal_forwarding_rules_config : config.region => config
+ } : {}
+
+ provider = google-beta
+ project = var.project_id
+ name = "${var.name}-internal-managed-http-${each.key}"
+ target = google_compute_target_http_proxy.default[0].self_link
+ port_range = var.http_port
+ labels = var.labels
+ load_balancing_scheme = var.load_balancing_scheme
+ network = local.internal_network
+ subnetwork = each.value.subnetwork
+ ip_address = each.value.address
+}
+
resource "google_compute_global_forwarding_rule" "https" {
provider = google-beta
project = var.project_id
- count = var.ssl ? 1 : 0
+ count = var.ssl && !local.is_internal_managed ? 1 : 0
name = "${var.name}-https"
target = google_compute_target_https_proxy.default[0].self_link
ip_address = local.address
@@ -69,9 +87,26 @@ resource "google_compute_global_forwarding_rule" "https" {
network = local.internal_network
}
+resource "google_compute_global_forwarding_rule" "internal_managed_https" {
+ for_each = var.ssl && local.is_internal_managed ? {
+ for config in var.internal_forwarding_rules_config : config.region => config
+ } : {}
+
+ provider = google-beta
+ project = var.project_id
+ name = "${var.name}-internal-managed-https-${each.key}"
+ target = google_compute_target_https_proxy.default[0].self_link
+ port_range = var.https_port
+ labels = var.labels
+ load_balancing_scheme = var.load_balancing_scheme
+ network = local.internal_network
+ subnetwork = each.value.subnetwork
+ ip_address = each.value.address
+}
+
resource "google_compute_global_address" "default" {
provider = google-beta
- count = local.is_internal ? 0 : var.create_address ? 1 : 0
+ count = local.is_internal_self_managed || local.is_internal_managed ? 0 : var.create_address ? 1 : 0
project = var.project_id
name = "${var.name}-address"
ip_version = "IPV4"
@@ -83,7 +118,7 @@ resource "google_compute_global_address" "default" {
resource "google_compute_global_forwarding_rule" "http_ipv6" {
provider = google-beta
project = var.project_id
- count = (var.enable_ipv6 && local.create_http_forward) ? 1 : 0
+ count = (var.enable_ipv6 && local.create_http_forward && !local.is_internal_managed) ? 1 : 0
name = "${var.name}-ipv6-http"
target = google_compute_target_http_proxy.default[0].self_link
ip_address = local.ipv6_address
@@ -93,10 +128,26 @@ resource "google_compute_global_forwarding_rule" "http_ipv6" {
network = local.internal_network
}
+resource "google_compute_global_forwarding_rule" "internal_managed_http_ipv6" {
+ for_each = var.enable_ipv6 && local.create_http_forward && local.is_internal_managed ? {
+ for config in var.internal_forwarding_rules_config : config.region => config
+ } : {}
+
+ provider = google-beta
+ project = var.project_id
+ name = "${var.name}-internal-managed-http-ipv6-${each.key}"
+ target = google_compute_target_http_proxy.default[0].self_link
+ port_range = "80"
+ labels = var.labels
+ load_balancing_scheme = var.load_balancing_scheme
+ subnetwork = each.value.subnetwork
+ ip_address = each.value.address
+}
+
resource "google_compute_global_forwarding_rule" "https_ipv6" {
provider = google-beta
project = var.project_id
- count = var.enable_ipv6 && var.ssl ? 1 : 0
+ count = var.enable_ipv6 && var.ssl && !local.is_internal_managed ? 1 : 0
name = "${var.name}-ipv6-https"
target = google_compute_target_https_proxy.default[0].self_link
ip_address = local.ipv6_address
@@ -106,9 +157,25 @@ resource "google_compute_global_forwarding_rule" "https_ipv6" {
network = local.internal_network
}
+resource "google_compute_global_forwarding_rule" "internal_managed_https_ipv6" {
+ for_each = var.enable_ipv6 && var.ssl && local.is_internal_managed ? {
+ for config in var.internal_forwarding_rules_config : config.region => config
+ } : {}
+
+ provider = google-beta
+ project = var.project_id
+ name = "${var.name}-internal-managed-https-ipv6-${each.key}"
+ target = google_compute_target_https_proxy.default[0].self_link
+ port_range = "443"
+ labels = var.labels
+ load_balancing_scheme = var.load_balancing_scheme
+ subnetwork = each.value.subnetwork
+ ip_address = each.value.address
+}
+
resource "google_compute_global_address" "default_ipv6" {
provider = google-beta
- count = local.is_internal ? 0 : (var.enable_ipv6 && var.create_ipv6_address) ? 1 : 0
+ count = local.is_internal_self_managed || local.is_internal_managed ? 0 : (var.enable_ipv6 && var.create_ipv6_address) ? 1 : 0
project = var.project_id
name = "${var.name}-ipv6-address"
ip_version = "IPV6"
diff --git a/modules/frontend/metadata.display.yaml b/modules/frontend/metadata.display.yaml
index 94428c24..6622c464 100644
--- a/modules/frontend/metadata.display.yaml
+++ b/modules/frontend/metadata.display.yaml
@@ -76,6 +76,11 @@ spec:
load_balancing_scheme:
name: load_balancing_scheme
title: Load Balancing Scheme
+ enumValueLabels:
+ - label: EXTERNAL_MANAGED
+ value: EXTERNAL_MANAGED
+ - label: INTERNAL_MANAGED
+ value: INTERNAL_MANAGED
managed_ssl_certificate_domains:
name: managed_ssl_certificate_domains
title: Managed Ssl Certificate Domains
diff --git a/modules/frontend/metadata.yaml b/modules/frontend/metadata.yaml
index 39b549b2..4cd66e47 100644
--- a/modules/frontend/metadata.yaml
+++ b/modules/frontend/metadata.yaml
@@ -50,6 +50,8 @@ spec:
location: examples/https-gke
- name: https-redirect
location: examples/https-redirect
+ - name: internal-lb-cloud-run
+ location: examples/internal-lb-cloud-run
- name: lb-http-separate-frontend-and-backend
location: examples/lb-http-separate-frontend-and-backend
- name: mig-nat-http-lb
@@ -164,11 +166,11 @@ spec:
varType: map(string)
defaultValue: {}
- name: load_balancing_scheme
- description: Load balancing scheme type (EXTERNAL for classic external load balancer, EXTERNAL_MANAGED for Envoy-based load balancer, and INTERNAL_SELF_MANAGED for traffic director)
+ description: Load balancing scheme type (EXTERNAL for classic external load balancer, EXTERNAL_MANAGED for Envoy-based load balancer, INTERNAL_MANAGED for internal load balancer and INTERNAL_SELF_MANAGED for traffic director)
varType: string
defaultValue: EXTERNAL_MANAGED
- name: network
- description: Network for INTERNAL_SELF_MANAGED load balancing scheme
+ description: Network for internal load balancer
varType: string
defaultValue: default
- name: server_tls_policy
@@ -185,6 +187,15 @@ spec:
- name: http_keep_alive_timeout_sec
description: Specifies how long to keep a connection open, after completing a response, while there is no matching traffic (in seconds).
varType: number
+ - name: internal_forwarding_rules_config
+ description: List of internal managed forwarding rules config. One of 'address' or 'subnetwork' is required for each. It is only applicable for internal load balancer
+ varType: |-
+ list(object({
+ region = string
+ address = optional(string)
+ subnetwork = optional(string)
+ }))
+ defaultValue: []
outputs:
- name: external_ip
description: The external IPv4 assigned to the global fowarding rule.
@@ -198,6 +209,10 @@ spec:
- name: https_proxy
description: The HTTPS proxy used by this module.
type: string
+ - name: ip_address_internal_managed_http
+ description: The internal/external IP addresses assigned to the HTTP forwarding rules.
+ - name: ip_address_internal_managed_https
+ description: The internal/external IP addresses assigned to the HTTPS forwarding rules.
- name: ipv6_enabled
description: Whether IPv6 configuration is enabled on this load-balancer
type: bool
@@ -219,6 +234,8 @@ spec:
- roles/run.admin
- roles/iam.serviceAccountUser
- roles/certificatemanager.owner
+ - roles/vpcaccess.admin
+ - roles/iam.serviceAccountAdmin
services:
- cloudresourcemanager.googleapis.com
- storage-api.googleapis.com
@@ -227,6 +244,7 @@ spec:
- run.googleapis.com
- iam.googleapis.com
- certificatemanager.googleapis.com
+ - vpcaccess.googleapis.com
providerVersions:
- source: hashicorp/google
version: ">= 6.0, < 7"
diff --git a/modules/frontend/outputs.tf b/modules/frontend/outputs.tf
index df3dd025..7f25310f 100644
--- a/modules/frontend/outputs.tf
+++ b/modules/frontend/outputs.tf
@@ -14,6 +14,16 @@
* limitations under the License.
*/
+output "ip_address_internal_managed_http" {
+ description = "The internal/external IP addresses assigned to the HTTP forwarding rules."
+ value = [for rule in google_compute_global_forwarding_rule.internal_managed_http : rule.ip_address]
+}
+
+output "ip_address_internal_managed_https" {
+ description = "The internal/external IP addresses assigned to the HTTPS forwarding rules."
+ value = [for rule in google_compute_global_forwarding_rule.internal_managed_https : rule.ip_address]
+}
+
output "external_ip" {
description = "The external IPv4 assigned to the global fowarding rule."
value = local.address
diff --git a/modules/frontend/variables.tf b/modules/frontend/variables.tf
index be93c406..7f11bc84 100644
--- a/modules/frontend/variables.tf
+++ b/modules/frontend/variables.tf
@@ -156,13 +156,13 @@ variable "labels" {
}
variable "load_balancing_scheme" {
- description = "Load balancing scheme type (EXTERNAL for classic external load balancer, EXTERNAL_MANAGED for Envoy-based load balancer, and INTERNAL_SELF_MANAGED for traffic director)"
+ description = "Load balancing scheme type (EXTERNAL for classic external load balancer, EXTERNAL_MANAGED for Envoy-based load balancer, INTERNAL_MANAGED for internal load balancer and INTERNAL_SELF_MANAGED for traffic director)"
type = string
default = "EXTERNAL_MANAGED"
}
variable "network" {
- description = "Network for INTERNAL_SELF_MANAGED load balancing scheme"
+ description = "Network for internal load balancer"
type = string
default = "default"
}
@@ -198,3 +198,13 @@ variable "http_keep_alive_timeout_sec" {
type = number
default = null
}
+
+variable "internal_forwarding_rules_config" {
+ description = "List of internal managed forwarding rules config. One of 'address' or 'subnetwork' is required for each. It is only applicable for internal load balancer"
+ type = list(object({
+ region = string
+ address = optional(string)
+ subnetwork = optional(string)
+ }))
+ default = []
+}
diff --git a/modules/serverless_negs/metadata.yaml b/modules/serverless_negs/metadata.yaml
index 1ba53db8..f709bc65 100644
--- a/modules/serverless_negs/metadata.yaml
+++ b/modules/serverless_negs/metadata.yaml
@@ -50,6 +50,8 @@ spec:
location: examples/https-gke
- name: https-redirect
location: examples/https-redirect
+ - name: internal-lb-cloud-run
+ location: examples/internal-lb-cloud-run
- name: lb-http-separate-frontend-and-backend
location: examples/lb-http-separate-frontend-and-backend
- name: mig-nat-http-lb
@@ -294,6 +296,8 @@ spec:
- roles/run.admin
- roles/iam.serviceAccountUser
- roles/certificatemanager.owner
+ - roles/vpcaccess.admin
+ - roles/iam.serviceAccountAdmin
services:
- cloudresourcemanager.googleapis.com
- storage-api.googleapis.com
@@ -302,6 +306,7 @@ spec:
- run.googleapis.com
- iam.googleapis.com
- certificatemanager.googleapis.com
+ - vpcaccess.googleapis.com
providerVersions:
- source: hashicorp/google
version: ">= 6.0, < 7"
diff --git a/test/integration/internal-lb-cloud-run/internal_lb_cloud_run_test.go b/test/integration/internal-lb-cloud-run/internal_lb_cloud_run_test.go
new file mode 100644
index 00000000..6472a313
--- /dev/null
+++ b/test/integration/internal-lb-cloud-run/internal_lb_cloud_run_test.go
@@ -0,0 +1,47 @@
+// Copyright 2024 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.
+
+package internal_lb_cloud_run
+
+import (
+ "testing"
+
+ "net/http"
+
+ "github.com/GoogleCloudPlatform/cloud-foundation-toolkit/infra/blueprint-test/pkg/tft"
+ "github.com/GoogleCloudPlatform/cloud-foundation-toolkit/infra/blueprint-test/pkg/utils"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestInternalLbCloudRun(t *testing.T) {
+ bpt := tft.NewTFBlueprintTest(t)
+
+ bpt.DefineVerify(func(assert *assert.Assertions) {
+ bpt.DefaultVerify(assert)
+
+ cloudRunURIs := bpt.GetStringOutputList("external_cloudrun_uris")
+
+ assertHttp := utils.NewAssertHTTP()
+
+ for _, uri := range cloudRunURIs {
+ httpRequest, err := http.NewRequest("GET", uri, nil)
+ if err != nil {
+ t.Fatalf("Failed to create HTTP request for %s: %v", uri, err)
+ }
+ assertHttp.AssertResponse(t, httpRequest, http.StatusOK)
+ }
+ })
+
+ bpt.Test()
+}
diff --git a/test/setup/iam.tf b/test/setup/iam.tf
index 6cba4dca..033e829d 100644
--- a/test/setup/iam.tf
+++ b/test/setup/iam.tf
@@ -20,7 +20,9 @@ locals {
"roles/compute.admin",
"roles/run.admin",
"roles/iam.serviceAccountUser",
- "roles/certificatemanager.owner"
+ "roles/certificatemanager.owner",
+ "roles/vpcaccess.admin",
+ "roles/iam.serviceAccountAdmin"
]
int_required_folder_roles = [
"roles/compute.xpnAdmin"
diff --git a/test/setup/main.tf b/test/setup/main.tf
index c158fa58..3d51ae0c 100644
--- a/test/setup/main.tf
+++ b/test/setup/main.tf
@@ -36,6 +36,7 @@ module "project-ci-lb-http" {
"run.googleapis.com",
"iam.googleapis.com",
"certificatemanager.googleapis.com",
+ "vpcaccess.googleapis.com",
]
}
@@ -61,5 +62,6 @@ module "project-ci-lb-http-1" {
"run.googleapis.com",
"iam.googleapis.com",
"certificatemanager.googleapis.com",
+ "vpcaccess.googleapis.com",
]
}