Recently I was wondering if I could deploy a Google-managed wildcard SSL certificate on my Global External HTTPS Load Balancer. In this blog, I will show you step by step how you can deploy a Global HTTPS Load Balancer using a Google-managed wildcard SSL certificate.
Background Research
Google-managed SSL certificates for Cloud Load Balancing by default do not support wildcard common names when provisioning load balancers according to this documentation. However, doing a quick search through the Google Cloud Platform documentation, I was led to the Certificate Manager service. It appears that the Certificate Manager service does support Wildcard common names. So, how do we attach certificates from the Certificate Manager to a Global External HTTPS Load Balancer?
Compatibility
First I wanted to check if there was native integration between Cloud Load Balancing and the Certificate Manager. I found an interesting comparison between Certificates and Google Cloud load balancers. The comparison shows which load balancers are compatible with the Certificate Manager, and as luck will have it, the Global External HTTPS load balancer is compatible!
Domain authorization
The next step was to identify which domain authorization method supports wildcard common names. The Certificate Manager requires to configure domain authorization for Google-managed SSL certificates, to prove ownership of the domain(s) of the SSL certificate. Google Cloud Platform provides two options to accomplish this:
- Load Balancer Authorization
- DNS authorization
Load Balancer authorization
Load balancer authorization is a more basic approach, which does not require any additional DNS changes and is therefore faster to configure, but the attached load balancer authorization does however not support wildcard common names.
DNS authorization
DNS authorization requires additional DNS configuration by adding DNS records to proof ownership by using Cloud DNS or a third-party DNS solution. DNS authorization does support wildcard common names. This makes this the only viable path for implementation.
Deploy the Global HTTPS Load Balancer
Important: Make sure you have configured your Cloud Domain and use the Cloud DNS provider when using these examples.
We will be using Terraform in our deployment examples, as it’s considered best practice to strive for Infrastructure as Code (IaC) wherever possible.
To deploy a Global Load Balancer using a Google-managed wildcard SSL certificate, 3 main components are configured:
- Cloud DNS
- Certificate Manager
- Global HTTPS Load Balancer
Create public DNS zone in Cloud DNS
Before creating the load balancer, first create a public DNS zone in Cloud DNS.
## Enable the Cloud DNS API ##
resource "google_project_service" "cloud_dns" {
service = "dns.googleapis.com"
}
## Public Cloud DNS zone. Make sure to configure your domain under Google Domains to use Cloud DNS ##
resource "google_dns_managed_zone" "public_dns_zone" {
name = "public-dns-zone"
dns_name = "example.com."
description = "Public DNS zone for example.com"
lifecycle {
prevent_destroy = true
}
}
Next, configure the Certificate Manager using DNS authorization and wildcard common names.
## Certificate manager resources to provision a wildcard SSL certificate for a Load Balancer. Requires a Public DNS zone ##
## Enable the certificate manager API ##
resource "google_project_service" "certificate_manager" {
service = "certificatemanager.googleapis.com"
}
## Configure DNS authorization to provide the ACME challenge DNS records ##
resource "google_certificate_manager_dns_authorization" "dns_authorization" {
name = "dns-authorization"
description = "DNS authorization for example.com to support wildcard certificates"
domain = "example.com"
}
## Provision a wildcard managed SSL certificate using DNS authorization ##
resource "google_certificate_manager_certificate" "wildcard_ssl_certificate" {
name = "wildcard-ssl-certificate"
description = "Wildcard certificate for ${local.fqdn} and sub-domains"
managed {
domains = ["example.com", "*.example.com"]
dns_authorizations = [
google_certificate_manager_dns_authorization.dns_authorization.id
]
}
}
## Certificate map resource to reference to from a forwarding rule ##
resource "google_certificate_manager_certificate_map" "certificate_map" {
name = "certificate-map"
description = "${local.fqdn} certificate map containing the domain names and sub-domains names for the SSL certificate"
}
## Certificate map entry for the top-level domain ##
resource "google_certificate_manager_certificate_map_entry" "domain_certificate_entry" {
name = "domain-cert-entry"
description = "example.com certificate entry"
map = google_certificate_manager_certificate_map.certificate_map.name
certificates = [google_certificate_manager_certificate.wildcard_ssl_certificate.id]
hostname = "example.com"
}
## Certificate map entry for the sub domain
resource "google_certificate_manager_certificate_map_entry" "sub_domain_certificate_entry" {
name = "sub-domain-entry"
description = "*.example.com certificate entry"
map = google_certificate_manager_certificate_map.certificate_map.name
certificates = [google_certificate_manager_certificate.wildcard_ssl_certificate.id]
hostname = "*.example.com"
}
The google_certificate_manager_dns_authorization
resource outputs the required DNS information to complete the DNS authorization setup which must be added to the earlier created DNS zone. Add the following DNS record:
## DNS authorization record ##
resource "google_dns_record_set" "dns_authorization_wildcard_certificate" {
name = google_certificate_manager_dns_authorization.dns_authorization.dns_resource_record[0].name
managed_zone = google_dns_managed_zone.public_dns_zone.name
type = google_certificate_manager_dns_authorization.dns_authorization.dns_resource_record[0].type
ttl = 300
rrdatas = [google_certificate_manager_dns_authorization.dns_authorization.dns_resource_record[0].data]
}
Configure external IP-address
To allow for a smooth deployment of the load balancer, we will configure an external IP-address for the Global HTTPS Load Balancer
# Load balancer IP
resource "google_compute_global_address" "lb_ip_address" {
name = "example-lb-ip"
description = "Public IP address of the Global HTTPS load balancer"
}
Update DNS zone with appropriate records
Add Domain name and wildcard sub-domain DNS records to the DNS zone
## Global load balancer DNS records ##
resource "google_dns_record_set" "global_load_balancer_sub_domain" {
managed_zone = google_dns_managed_zone.public_dns_zone.name
name = "*.${google_dns_managed_zone.public_dns_zone.dns_name}"
type = "A"
rrdatas = [google_compute_global_address.lb_ip_address.address]
}
resource "google_dns_record_set" "global_load_balancer_top_level_domain" {
managed_zone = google_dns_managed_zone.public_dns_zone.name
name = google_dns_managed_zone.public_dns_zone.dns_name
type = "A"
rrdatas = [google_compute_global_address.lb_ip_address.address]
}
Create Load Balancer resources
# HTTPS load balancer
resource "google_compute_global_forwarding_rule" "https_forwarding_rule" {
name = "https-forwarding-rule"
description = "Global external load balancer"
ip_address = google_compute_global_address.lb_ip_address.id
port_range = "443"
target = google_compute_target_https_proxy.https_proxy.self_link
}
# HTTPS proxy
resource "google_compute_target_https_proxy" "https_proxy" {
name = "https-webserver-proxy"
description = "HTTPS Proxy mapping for the Load balancer including wildcard ssl certificate"
url_map = google_compute_url_map.url_map.self_link
certificate_map = "//${google_project_service.certificate_manager.service}/${google_certificate_manager_certificate_map.certificate_map.id}"
}
# HTTP proxy
resource "google_compute_global_forwarding_rule" "http_forwarding_rule" {
name = "http-forwarding-rule"
description = "Global external load balancer HTTP redirect"
ip_address = google_compute_global_address.lb_ip_address.id
port_range = "80"
target = google_compute_target_http_proxy.http_proxy.self_link
}
## HTTPS redirect proxy
resource "google_compute_target_http_proxy" "http_proxy" {
name = "http-webserver-proxy"
description = "Redirect proxy mapping for the Load balancer"
url_map = google_compute_url_map.http_https_redirect.self_link
}
# Default URL map
resource "google_compute_url_map" "url_map" {
name = "url-map"
description = "Url mapping to the backend services"
}
# Redirect URL map
resource "google_compute_url_map" "http_https_redirect" {
name = "http-https-redirect"
description = "HTTP Redirect map"
default_url_redirect {
https_redirect = true
redirect_response_code = "MOVED_PERMANENTLY_DEFAULT"
strip_query = false
}
}
By using the certificates_map
argument we are able to reference the earlier created certificate map and use the wildcard SSL certificate.
Security considerations
Using a wildcard SSL certificate means that your top-level domain and all your sub-domains would use the same SSL certificate. This means that if a Google-managed SSL certificate is compromised, it will affect all the HTTPS applications which are behind the Global External HTTPS Load Balancer using this certificate. You should always consider if a wildcard SSL certificate fits within your risk appetite.
Conclusion
Attaching a Google-managed wildcard SSL certificate to a Global External HTTPS Load Balancer is possible when using the Certificate Manager service and Cloud DNS using DNS authorization. Using this approach will provide a maintainable and cloud-native approach that removes additional configuration of certificates for sub-domains attached to a Global External HTTPS Load Balancer.
Photo from Parsoa Khorsand from Unsplash