The other answers are very good, but I was very motivated to find a way to migrate to a GCP load balancer without planning for downtime where we basically just sit and wait for certificates to be issued. Adding my own answer since this question got quite a lot of traffic and it turns out that downtime is not necessary with some planning and testing.
Here's how I did it:
- Issue temporary Let's Encrypt certificates for example.com.
- Import the certificates as self-managed certificates.
- Set up the load balancer to use the self-managed certificates.
- Update DNS records to point to the load balancer.
- Create Google-managed certificates and assign them as a second certificate, beside the self-managed certificate.
- Wait for the Google-managed certificate to be
ACTIVE
. This can take a long time. This is where there would be downtime without the self-managed certificate.
- Wait 30 minutes for the certificate to propagate to all Google Front Ends (GFEs).
- There's now two certificates assigned to the load balancer. Update it to only use the Google-managed certificate. Done!
Details
To summarize the issue: Google's managed certificates require a DNS record pointing to a load balancer with the certificate already assigned or they won't be issued. This creates an issue, since issuing the certificate can take up to an hour and we don't want SSL errors during this time.
The workaround I found was to use self-managed certificates during the migration and switch over to the Google managed certificates once our domain was pointing to the GCP load balancer and certificates had already been issued.
I used Let's Encrypt certificates, but others will work as well. A benefit of this was that we were already using Let's Encrypt certificates, so I didn't have to worry about certificate compatibility.
Here's a simplified version of what I did. The load balancer's target proxy will be called my-target-proxy
, the certificates called lb-certificate-letsencrypt
and lb-certificate-managed
. The domain names are example.com
and subdomain.example.com
.
Prerequisites:
Generate a new certificate to use as the self-managed certificate, signed by Let's Encrypt:
openssl genrsa -out letsencrypt.pem 2048
Create an openssl configuration file:
openssl.conf
[req]
default_bits = 2048
req_extensions = extension_requirements
distinguished_name = dn_requirements
[extension_requirements]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @sans_list
[dn_requirements]
countryName = Country Name (2 letter code)
stateOrProvinceName = State or Province Name (full name)
localityName = Locality Name (eg, city)
0.organizationName = Organization Name (eg, company)
organizationalUnitName = Organizational Unit Name (eg, section)
commonName = Common Name (e.g. server FQDN or YOUR name)
emailAddress = Email Address
[sans_list]
DNS.1 = example.com
DNS.2 = subdomain.example.com
Generate a certificate signing request:
openssl req -new -key letsencrypt.pem -out letsencrypt.csr -config openssl.conf
Get a signed certificate from Let's Encrypt:
certbot certonly --csr letsencrypt.csr --manual --preferred-challenges dns
Update the DNS records indicated by certbot to verify ownership. Other challenges might work too, but DNS seemed easiest.
Make a note of which file is the full certificate chain and replace 0003_chain.pem
in the example if necessary:
Full certificate chain is saved at: ...
Upload and create the self-managed certificate in GCP:
gcloud compute ssl-certificates create lb-certificate-letsencrypt \
--certificate=0003_chain.pem \
--private-key=letsencrypt.pem \
--global
Create the load balancer that you're migrating to, or configure it to use the self-managed certificate:
gcloud beta compute target-https-proxies create my-target-proxy \
--ssl-certificates=lb-certificate-letsencrypt [url-map and other options]
# Or
gcloud beta compute target-https-proxies update my-target-proxy \
--ssl-certificates=lb-certificate-letsencrypt
Update DNS records to point to the IP for your load balancer. It should now be able to terminate TLS for example.com and subdomain.example.com. You can test this step by adding a record for example.com in your hosts file, pointing to the load balancer IP. John Hanley's answer gives a lot of good advice on this.
Create the managed certificate:
gcloud compute ssl-certificates create lb-certificate-managed \
--domains=example.com,subdomain.example.com \
--global
Wildcards are not supported by Google-managed certificates, so make sure to list all domains in use.
Assign it to the target proxy together with the self-managed certificate. Certificates will not be provisioned until they're assigned to a proxy:
gcloud beta compute target-https-proxies update my-target-proxy \
--ssl-certificates=lb-certificate-letsencrypt,lb-certificate-managed
Check the status:
gcloud compute ssl-certificates describe lb-certificate-managed
Wait until status
changes from PROVISIONING
to ACTIVE
- any other status is an error that should be investigated. "Provisioning a Google-managed certificate might take up to 60 minutes." according to the docs (Let's Encrypt does the same thing in seconds...).
It might take an additional 30 minutes to be available for use by a load balancer.
Therefore, wait 30 minutes after the status has changed to ACTIVE
.
Update the target proxy to only use the Google-managed certificate:
gcloud beta compute target-https-proxies update my-target-proxy \
--ssl-certificates=lb-certificate-managed
It can take a while for the new setting to propagate. Verify the issuer for the endpoint in the browser or using openssl:
openssl s_client -connect example.com:443 -showcerts \
-CAfile /etc/ssl/certs/ca-certificates.crt <<< Q
Issuer should now be "Google Trust Services LLC" instead of "Let's Encrypt".
The self-managed Let's Encrypt certificate can now be removed, or kept around until it expires in case there's any issues with the managed certificate.
To clean up the unused self-managed Let's Encrypt certificate, run:
gcloud compute ssl-certificates delete lb-certificate-letsencrypt