/** * Copyright 2023 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 { gclb_create = var.custom_domain == null ? false : true iap_sa_email = try(google_project_service_identity.iap_sa[0].email, "") } module "project" { source = "../../../modules/project" billing_account = (var.project_create != null ? var.project_create.billing_account_id : null ) parent = (var.project_create != null ? var.project_create.parent : null ) name = var.project_id services = [ "run.googleapis.com", "compute.googleapis.com", "iap.googleapis.com" ] project_create = var.project_create != null } # Cloud Run service module "cloud_run" { source = "../../../modules/cloud-run" project_id = module.project.project_id name = var.run_svc_name region = var.region containers = { default = { image = var.image } } iam = { "roles/run.invoker" = (local.gclb_create && var.iap.enabled ? ["serviceAccount:${local.iap_sa_email}"] : ["allUsers"] ) } ingress_settings = var.ingress_settings } # Reserved static IP for the Load Balancer resource "google_compute_global_address" "default" { count = local.gclb_create ? 1 : 0 project = module.project.project_id name = "glb-ip" } # Global L7 HTTPS Load Balancer in front of Cloud Run module "glb" { source = "../../../modules/net-lb-app-ext" count = local.gclb_create ? 1 : 0 project_id = module.project.project_id name = "glb" address = google_compute_global_address.default[0].address backend_service_configs = { default = { backends = [ { backend = "neg-0" } ] health_checks = [] port_name = "http" security_policy = try(google_compute_security_policy.policy[0].name, null) iap_config = try({ oauth2_client_id = google_iap_client.iap_client[0].client_id, oauth2_client_secret = google_iap_client.iap_client[0].secret }, null) } } health_check_configs = {} neg_configs = { neg-0 = { cloudrun = { region = var.region target_service = { name = var.run_svc_name } } } } protocol = "HTTPS" ssl_certificates = { managed_configs = { default = { domains = [var.custom_domain] } } } } # Cloud Armor configuration resource "google_compute_security_policy" "policy" { count = local.gclb_create && var.security_policy.enabled ? 1 : 0 name = "cloud-run-policy" project = module.project.project_id rule { action = "deny(403)" priority = 1000 match { versioned_expr = "SRC_IPS_V1" config { src_ip_ranges = var.security_policy.ip_blacklist } } description = "Deny access to list of IPs" } rule { action = "deny(403)" priority = 900 match { expr { expression = "request.path.matches(\"${var.security_policy.path_blocked}\")" } } description = "Deny access to specific URL paths" } rule { action = "allow" priority = "2147483647" match { versioned_expr = "SRC_IPS_V1" config { src_ip_ranges = ["*"] } } description = "Default rule" } } # Identity-Aware Proxy (IAP) or OAuth brand (see OAuth consent screen) # Note: # Only "Organization Internal" brands can be created programmatically # via API. To convert it into an external brand please use the GCP # Console. # Brands can only be created once for a Google Cloud project and the # underlying Google API doesn't support DELETE or PATCH methods. # Destroying a Terraform-managed Brand will remove it from state but # will not delete it from Google Cloud. resource "google_iap_brand" "iap_brand" { count = local.gclb_create && var.iap.enabled ? 1 : 0 project = module.project.project_id # Support email displayed on the OAuth consent screen. The caller must be # the user with the associated email address, or if a group email is # specified, the caller can be either a user or a service account which # is an owner of the specified group in Cloud Identity. support_email = var.iap.email application_title = var.iap.app_title } # IAP owned OAuth2 client # Note: # Only internal org clients can be created via declarative tools. # External clients must be manually created via the GCP console. # Warning: # All arguments including secret will be stored in the raw state as plain-text. resource "google_iap_client" "iap_client" { count = local.gclb_create && var.iap.enabled ? 1 : 0 display_name = var.iap.oauth2_client_name brand = google_iap_brand.iap_brand[0].name } # IAM policy for IAP # For simplicity we use the same email as support_email and authorized member resource "google_iap_web_iam_member" "iap_iam" { count = local.gclb_create && var.iap.enabled ? 1 : 0 project = module.project.project_id role = "roles/iap.httpsResourceAccessor" member = "user:${var.iap.email}" } # SA service agent for IAP, which invokes CR # Note: # Once created, this resource cannot be updated or destroyed. These actions are a no-op. resource "google_project_service_identity" "iap_sa" { provider = google-beta count = local.gclb_create && var.iap.enabled ? 1 : 0 project = module.project.project_id service = "iap.googleapis.com" }