If you have unmanaged GCP VM instances running services on insecure ports (e.g. Apache HTTP on port 80), one way to secure the public external traffic is to create an external GCP HTTPS load balancer.
Conceptually, we want to expose a secure front to otherwise insecure services.
While the preferred method would be to secure the client communication natively (easy enough using our Apache example), this is not always an option when dealing with unmanaged VM instances that contain legacy solutions.
This security stance follows the same model one might follow on-premise, where either a commercial load balancer or NGINX/HAProxy is used as a secure front to an insecure backend pool of VM.
Solution Overview
Our ultimate goal is to take two VM instances that only speak on insecure ports (Apache on port 80), and expose their services instead on a GCP global External HTTPS loadbalancer using HTTPS on port 443.
This can be accomplished by creating a backing service with unmanaged instance groups for VMs in each zone as shown below.
We then create and wire together the health-checks, backend-services, url-maps, target-https-proxies, and forwarding rule objects as shown in the diagram.
The rest of the this article will detail the creation of these objects.
GCP network prerequisites
There is one GCP network prerequisites for an external HTPS load balancer, you must create a firewall rule to allow health checks.
As noted in the Google documentation, the health checks will come from two Google source IP ranges: 35.191.0.0/16 or 130.211.0.0/22.
network_name=mynetwork gcloud compute firewall-rules create fw-allow-health-checks \ --network=${network_name} \ --action=ALLOW \ --direction=INGRESS \ --source-ranges=35.191.0.0/16,130.211.0.0/22 \ --target-tags=allow-health-checks \ --rules=tcp
The VMs in this article “apache1-10-0-90-0” and “apache2-10-0-90-0” are both tagged with “allow-health-checks” to participate in this firewall rule.
gcloud compute instances add-tags apache1-10-0-90-0 --tags=allow-health-checks --zone=us-east1-b gcloud compute instances add-tags apache2-10-0-90-0 --tags=allow-health-checks --zone=us-east1-c
Here is an example of the network firewall being done with Terraform, and a terraform example of tagging VM instances using Terraform and its variables being passed.
Notice that for our global HTTPS LB, a proxy-only subnet is not necessary. It would be necessary if this HTTPS LB was regional.
Unmanaged VM instances running insecure service
For this article, we will have two unmanaged VM instance running Apache on port 80. These VMs are named:
- apache1-10-0-90-0 running on us-east1-a
- apache2-10-0-90-0 running on us-east2-b
Create unmanaged instance groups for the VMs in each zone, with a named port on 80.
project_id=$(gcloud config get project) region=us-east1 instance_group_prefix=lb-ig # for creating global objects location_flag="--global" ig_name=${instance_group_prefix}-a gcloud compute instance-groups unmanaged create $ig_name --zone=${region}-a gcloud compute instance-groups unmanaged set-named-ports $ig_name --named-ports=http:80 --zone=${region}-a gcloud compute instance-groups unmanaged add-instances $ig_name --instances=apache1-10-0-90-0 --zone=${region}-a ig_name=${instance_group_prefix}-b gcloud compute instance-groups unmanaged create $ig_name --zone=${region}-b gcloud compute instance-groups unmanaged set-named-ports $ig_name --named-ports=http:80 --zone=${region}-b gcloud compute instance-groups unmanaged add-instances $ig_name --instances=apache2-10-0-90-0 --zone=${region}-b
Health check
Create a health check for the backend-service.
healthcheck_name=extb-health gcloud compute health-checks create http $healthcheck_name --host='' --request-path=/index.html --port=80 --enable-logging $location_flag
Backend Service
Create a backend service.
backend_name=extlb-backend gcloud compute backend-services create $backend_name --health-checks=$healthcheck_name --port-name=http --protocol=HTTP --load-balancing-scheme=EXTERNAL --enable-logging --logging-sample-rate=1 $location_flag
Then add its two unmanaged instance group members.
gcloud compute backend-services add-backend $backend_name --instance-group=${instance_group_prefix}-a --instance-group-zone=${region}-a $location_flag gcloud compute backend-services add-backend $backend_name --instance-group=${instance_group_prefix}-b --instance-group-zone=${region}-b $location_flag
SSL Certificate
Create the TLS certificate that will be used for secure communication. We will use a self-signed cert, but you are free to use a commercial one.
domain=httpslb.fabianlee.org openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \ -keyout /tmp/$FQDN.key -out /tmp/$FQDN.crt \ -subj "/C=US/ST=CA/L=SFO/O=myorg/CN=$FQDN"
Load the certificate into GCP.
gcloud compute ssl-certificates create lbcert1 --certificate=/tmp/$domain.crt --private-key=/tmp/$domain.key --project=$project_id $location_flag
URL Map
The URL map directs traffic based on the request. The name of the URL map object is what the cloud console shows as the load balancer name.
lb_name=extlb-lb1 gcloud compute url-maps create $lb_name --default-service=$backend_name $location_flag
Target HTTPS Proxies
This is the actual proxy-based load balancer entity.
target_https_proxy_name=extlb-target-https-proxy gcloud compute target-https-proxies create $target_https_proxy_name --url-map $lb_name --ssl-certificates=lbcert1 $location_flag
Forwarding Rule
Finally, you must create the forwarding rule that exposes an IP address and port for the load balancer. A forwarding rule can only expose a single port.
fwd_rule_name=extlb-frontend gcloud compute forwarding-rules create $fwd_rule_name --load-balancing-scheme=EXTERNAL --ports=443 --target-https-proxy=$target_https_proxy_name $location_flag
The IP address of the global HTTS load balancer can be retrieved using:
gcloud compute forwarding-rules describe $fwd_rule_name --global | grep -i IPAddress
Cloud Console UI
Here is the view from the cloud console.
Script
If you want a full example, see my create-https-lb.sh on github.
REFERENCES
google ref, external HTTPS LB overview
google ref, external HTTPS LB architecture explanation and diagram
stackoverflow, creating https lb with diagram
google, google loadbalancing health checks
google, creating LB health checks
chainerweb.com, loadbalancer and instancegroups for GCP lb with terraform
google ref, gcloud unmanaged instance groups
google ref, gcloud backend-services
nbtechsolutions, gcp https lb with gcloud
realkinetic blog, GCP external loadbalancer with managed VM instances and gcloud
stackoverflow, good answer describing GCP LB constructs