diff --git a/terraform/README.md b/terraform/README.md index bade381d7..8925e5d68 100644 --- a/terraform/README.md +++ b/terraform/README.md @@ -146,9 +146,9 @@ Terraform module. # Cloud Monitoring # monitoring-host-project = "example" - adminapi-host = "adminapi.example.org" - apiserver-host = "apiserver.example.org" - server-host = "example.org" + adminapi_hosts = ["adminapi.example.org"] + apiserver_hosts = ["apiserver.example.org"] + server_hosts = ["example.org"] notification-email = "example+alert@google.com" } @@ -241,6 +241,14 @@ database_max_connections = 256 ### Debugging +#### Custom hosts + +Using custom hosts (domains) for the services requires a manual step of updating +DNS entries. Run Terraform once and get the `lb_ip` entry. Then, update your DNS +provider to point the A records to that IP address. Give DNS time to propagate +and then re-apply Terraform. DNS must be working for the certificates to +provision. + #### Cannot find firebase provider If you're getting an error like: diff --git a/terraform/alerting/probers.tf b/terraform/alerting/probers.tf index 9f8c5360a..15c6cc602 100644 --- a/terraform/alerting/probers.tf +++ b/terraform/alerting/probers.tf @@ -15,7 +15,7 @@ resource "google_monitoring_uptime_check_config" "https" { project = local.monitoring-host-project - for_each = toset(compact(concat([var.server-host, var.apiserver-host, var.adminapi-host], var.extra-hosts))) + for_each = toset(compact(concat(var.server_hosts, var.apiserver_hosts, var.adminapi_hosts, var.extra-hosts))) display_name = each.key timeout = "3s" diff --git a/terraform/alerting/variables.tf b/terraform/alerting/variables.tf index 7d32a83fe..501c42d72 100644 --- a/terraform/alerting/variables.tf +++ b/terraform/alerting/variables.tf @@ -15,22 +15,19 @@ variable "notification-email" { description = "Email address for alerts to go to." } -variable "server-host" { - type = string - default = "" - description = "Domain web ui is hosted on." +variable "server_hosts" { + type = list(string) + description = "List of domains upon which the web ui is served." } -variable "apiserver-host" { - type = string - default = "" - description = "Domain apiserver is hosted on." +variable "apiserver_hosts" { + type = list(string) + description = "List of domains upon which the apiserver is served." } -variable "adminapi-host" { - type = string - default = "" - description = "Domain adminapi is hosted on." +variable "adminapi_hosts" { + type = list(string) + description = "List of domains upon which the adminapi is served." } variable "extra-hosts" { diff --git a/terraform/service_admin_apiserver.tf b/terraform/service_admin_apiserver.tf index 95886961a..ea433d908 100644 --- a/terraform/service_admin_apiserver.tf +++ b/terraform/service_admin_apiserver.tf @@ -165,6 +165,8 @@ resource "google_cloud_run_service" "adminapi" { } resource "google_compute_region_network_endpoint_group" "adminapi" { + count = length(var.adminapi_hosts) > 0 ? 1 : 0 + name = "adminapi" provider = google-beta project = var.project @@ -178,35 +180,14 @@ resource "google_compute_region_network_endpoint_group" "adminapi" { } resource "google_compute_backend_service" "adminapi" { - count = local.enable_lb ? 1 : 0 + count = length(var.adminapi_hosts) > 0 ? 1 : 0 + provider = google-beta name = "adminapi" project = var.project backend { - group = google_compute_region_network_endpoint_group.adminapi.id - } -} - -resource "google_cloud_run_domain_mapping" "adminapi" { - for_each = var.adminapi_custom_domains - - location = var.cloudrun_location - name = each.key - - metadata { - namespace = var.project - } - - spec { - route_name = google_cloud_run_service.adminapi.name - force_override = true - } - - lifecycle { - ignore_changes = [ - spec[0].force_override - ] + group = google_compute_region_network_endpoint_group.adminapi[0].id } } @@ -218,6 +199,6 @@ resource "google_cloud_run_service_iam_member" "adminapi-public" { member = "allUsers" } -output "adminapi_url" { - value = google_cloud_run_service.adminapi.status.0.url +output "adminapi_urls" { + value = concat([google_cloud_run_service.adminapi.status.0.url], formatlist("https://%s", var.adminapi_hosts)) } diff --git a/terraform/service_apiserver.tf b/terraform/service_apiserver.tf index fdd7b6142..0d6525cc8 100644 --- a/terraform/service_apiserver.tf +++ b/terraform/service_apiserver.tf @@ -173,6 +173,8 @@ resource "google_cloud_run_service" "apiserver" { } resource "google_compute_region_network_endpoint_group" "apiserver" { + count = length(var.apiserver_hosts) > 0 ? 1 : 0 + name = "apiserver" provider = google-beta project = var.project @@ -186,35 +188,14 @@ resource "google_compute_region_network_endpoint_group" "apiserver" { } resource "google_compute_backend_service" "apiserver" { - count = local.enable_lb ? 1 : 0 + count = length(var.apiserver_hosts) > 0 ? 1 : 0 + provider = google-beta name = "apiserver" project = var.project backend { - group = google_compute_region_network_endpoint_group.apiserver.id - } -} - -resource "google_cloud_run_domain_mapping" "apiserver" { - for_each = var.apiserver_custom_domains - - location = var.cloudrun_location - name = each.key - - metadata { - namespace = var.project - } - - spec { - route_name = google_cloud_run_service.apiserver.name - force_override = true - } - - lifecycle { - ignore_changes = [ - spec[0].force_override - ] + group = google_compute_region_network_endpoint_group.apiserver[0].id } } @@ -226,6 +207,6 @@ resource "google_cloud_run_service_iam_member" "apiserver-public" { member = "allUsers" } -output "apiserver_url" { - value = google_cloud_run_service.apiserver.status.0.url +output "apiserver_urls" { + value = concat([google_cloud_run_service.apiserver.status.0.url], formatlist("https://%s", var.apiserver_hosts)) } diff --git a/terraform/service_server.tf b/terraform/service_server.tf index 52db87943..c5e96740a 100644 --- a/terraform/service_server.tf +++ b/terraform/service_server.tf @@ -212,6 +212,8 @@ resource "google_cloud_run_service" "server" { } resource "google_compute_region_network_endpoint_group" "server" { + count = length(var.server_hosts) > 0 ? 1 : 0 + name = "server" provider = google-beta project = var.project @@ -225,35 +227,14 @@ resource "google_compute_region_network_endpoint_group" "server" { } resource "google_compute_backend_service" "server" { - count = local.enable_lb ? 1 : 0 + count = length(var.server_hosts) > 0 ? 1 : 0 + provider = google-beta name = "server" project = var.project backend { - group = google_compute_region_network_endpoint_group.server.id - } -} - -resource "google_cloud_run_domain_mapping" "server" { - for_each = var.server_custom_domains - - location = var.cloudrun_location - name = each.key - - metadata { - namespace = var.project - } - - spec { - route_name = google_cloud_run_service.server.name - force_override = true - } - - lifecycle { - ignore_changes = [ - spec[0].force_override - ] + group = google_compute_region_network_endpoint_group.server[0].id } } @@ -265,6 +246,6 @@ resource "google_cloud_run_service_iam_member" "server-public" { member = "allUsers" } -output "server_url" { - value = google_cloud_run_service.server.status.0.url +output "server_urls" { + value = concat([google_cloud_run_service.server.status.0.url], formatlist("https://%s", var.server_hosts)) } diff --git a/terraform/variables.tf b/terraform/variables.tf index a99f84cd5..742901ec7 100644 --- a/terraform/variables.tf +++ b/terraform/variables.tf @@ -139,43 +139,25 @@ variable "redis_cache_size" { description = "Size of the Redis instance in GB." } -variable "adminapi_custom_domains" { - type = set(string) +variable "server_hosts" { + type = list(string) default = [] - description = "Custom domains to map for adminapi. These domains must already be verified by Google, and you must have a DNS CNAME record pointing to ghs.googlehosted.com in advance." + description = "List of domains upon which the web ui is served." } -variable "apiserver_custom_domains" { - type = set(string) +variable "apiserver_hosts" { + type = list(string) default = [] - description = "Custom domains to map for apiserver. These domains must already be verified by Google, and you must have a DNS CNAME record pointing to ghs.googlehosted.com in advance." + description = "List of domains upon which the apiserver is served." } -variable "server_custom_domains" { - type = set(string) +variable "adminapi_hosts" { + type = list(string) default = [] - description = "Custom domains to map for server. These domains must already be verified by Google, and you must have a DNS CNAME record pointing to ghs.googlehosted.com in advance." -} - -variable "server-host" { - type = string - default = "" - description = "Domain web ui is hosted on." -} - -variable "apiserver-host" { - type = string - default = "" - description = "Domain apiserver is hosted on." -} - -variable "adminapi-host" { - type = string - default = "" - description = "Domain adminapi is hosted on." + description = "List of domains upon which the adminapi is served." } variable "enx_redirect_domain" { diff --git a/terraform/verification-lb.tf b/terraform/verification-lb.tf index 0534e7d08..ad35e5ce8 100644 --- a/terraform/verification-lb.tf +++ b/terraform/verification-lb.tf @@ -13,17 +13,21 @@ # limitations under the License. locals { - enable_lb = var.server-host != "" && var.apiserver-host != "" && var.adminapi-host != "" + all_hosts = toset(concat(var.server_hosts, var.apiserver_hosts, var.adminapi_hosts)) + enable_lb = length(local.all_hosts) > 0 } resource "google_compute_global_address" "verification-server" { - count = local.enable_lb ? 1 : 0 + count = local.enable_lb ? 1 : 0 + name = "verification-server-address" project = var.project } # Redirects all requests to https resource "google_compute_url_map" "urlmap-http" { + count = local.enable_lb ? 1 : 0 + name = "https-redirect" provider = google-beta project = var.project @@ -35,54 +39,84 @@ resource "google_compute_url_map" "urlmap-http" { } resource "google_compute_url_map" "urlmap-https" { - count = local.enable_lb ? 1 : 0 + count = local.enable_lb ? 1 : 0 + name = "verification-server" provider = google-beta project = var.project default_service = google_compute_backend_service.server[0].id - host_rule { - hosts = [var.server-host] - path_matcher = "server" + // server + dynamic "host_rule" { + for_each = length(var.server_hosts) > 0 ? [1] : [] + + content { + path_matcher = "server" + hosts = var.server_hosts + } } - path_matcher { - name = "server" - default_service = google_compute_backend_service.server[0].id + dynamic "path_matcher" { + for_each = length(var.server_hosts) > 0 ? [1] : [] + + content { + name = "server" + default_service = google_compute_backend_service.server[0].id + } } - host_rule { - hosts = [var.apiserver-host] - path_matcher = "apiserver" + // apiserver + dynamic "host_rule" { + for_each = length(var.apiserver_hosts) > 0 ? [1] : [] + + content { + path_matcher = "apiserver" + hosts = var.apiserver_hosts + } } - path_matcher { - name = "apiserver" - default_service = google_compute_backend_service.apiserver[0].id + dynamic "path_matcher" { + for_each = length(var.apiserver_hosts) > 0 ? [1] : [] + + content { + name = "apiserver" + default_service = google_compute_backend_service.apiserver[0].id + } } - host_rule { - hosts = [var.adminapi-host] - path_matcher = "adminapi" + // adminapi + dynamic "host_rule" { + for_each = length(var.adminapi_hosts) > 0 ? [1] : [] + + content { + path_matcher = "adminapi" + hosts = var.adminapi_hosts + } } - path_matcher { - name = "adminapi" - default_service = google_compute_backend_service.adminapi[0].id + dynamic "path_matcher" { + for_each = length(var.adminapi_hosts) > 0 ? [1] : [] + + content { + name = "adminapi" + default_service = google_compute_backend_service.adminapi[0].id + } } } resource "google_compute_target_http_proxy" "http" { - count = local.enable_lb ? 1 : 0 + count = local.enable_lb ? 1 : 0 + provider = google-beta name = "verification-server" project = var.project - url_map = google_compute_url_map.urlmap-http.id + url_map = google_compute_url_map.urlmap-http[0].id } resource "google_compute_target_https_proxy" "https" { - count = local.enable_lb ? 1 : 0 + count = local.enable_lb ? 1 : 0 + name = "verification-server" project = var.project @@ -91,7 +125,8 @@ resource "google_compute_target_https_proxy" "https" { } resource "google_compute_global_forwarding_rule" "http" { - count = local.enable_lb ? 1 : 0 + count = local.enable_lb ? 1 : 0 + provider = google-beta name = "verification-server-http" project = var.project @@ -104,7 +139,8 @@ resource "google_compute_global_forwarding_rule" "http" { } resource "google_compute_global_forwarding_rule" "https" { - count = local.enable_lb ? 1 : 0 + count = local.enable_lb ? 1 : 0 + provider = google-beta name = "verification-server-https" project = var.project @@ -116,13 +152,34 @@ resource "google_compute_global_forwarding_rule" "https" { target = google_compute_target_https_proxy.https[0].id } +resource "random_id" "certs" { + count = local.enable_lb ? 1 : 0 + + byte_length = 4 + + keepers = { + domains = join(",", local.all_hosts) + } +} + resource "google_compute_managed_ssl_certificate" "default" { - count = local.enable_lb ? 1 : 0 - provider = google-beta + count = local.enable_lb ? 1 : 0 - name = "verification-cert" + provider = google-beta + name = "verification-certificates-${random_id.certs[0].hex}" + project = var.project managed { - domains = [var.server-host, var.apiserver-host, var.adminapi-host] + domains = local.all_hosts + } + + # This is to prevent destroying the cert while it's still attached to the load + # balancer. + lifecycle { + create_before_destroy = true } } + +output "lb_ip" { + value = google_compute_global_address.verification-server[0].address +}