Image for post
Image for post

Securing GKE with Managed SSL

Using Google Managed SSL Certificates with a GKE Cluster

There comes a time where you will need to secure web traffic for your web services on Kubernetes. Alright, that’s all the time. For GKE, you can do this with Google Managed SSL certificates.


Tool Requirements

  • Google Cloud SDK that is authorized to your google account and your account has access to a Google Project where you can manage GCE, GKE, and Cloud DNS.
  • Kubectl (pronounced koob-cuttle) is the Kubernetes client command line tool to interaction with the cluster and installing Kubernetes manifests.

Infrastructure Requirements

  • Registered Domain or Sub-Domain on Cloud DNS.
  • GKE Cluster (Kubernetes 1.16 or higher) configured scope to access Cloud DNS API.
  • Installation of ExternalDNS on GKE Cluster configured with access to update records on Cloud DNS.

Previous Article

In a previous article, I demonstrated how to configure ExternalDNS to update cloud DNS records (GKE and Cloud DNS must be in the same GCP project):

Deploy Application with SSL Support

We will need to use an Ingress resource to create our endpoint for L7 HTTP/S support. Below is a diagram the resources used in this exercise:

Image for post
Image for post
  • register a new DNS record that points to the external IP address of the load balancer (using ExternalDNS)
  • attach certificate that we declared earlier to the load balancer, which also completes the certificate provisioning process.

Deploy the Deployment Controller

First we can deploy a deployment to manage an create the pods hosting the web application. Create a file gce_ssl_deploy.yaml with the following contents:

kubectl create --filename gce_ssl_deploy.yaml

Deploy the ManagedCertificate CRD

Managing external load balancers on Google Cloud can be complex, as you’ll need to create forwarding rules, target proxy rules, register backend services, and the certificate, which is added to a HTTP target proxy.

MY_DNS_NAME=<put_your_domain_here> # hello.test.acme.comsed -i "s/\$MY_DNS_NAME/$MY_DNS_NAME/" gce_ssl_managed_cert.yaml
kubectl create --filename gce_ssl_managed_cert.yaml

Deploy the Service

We need to deploy the service resource with NodePort type (ClusterIP will not work with gce ingress). Create a file gce_ssl_service.yaml.

kubectl create --filename gce_ssl_service.yaml

Deploy the Ingress Resource

Now comes time for the final piece the ingress resources, which will read our desired certificate as well create an external load balancer on Google Cloud. Additionally, this will register a DNS record on Cloud DNS using external-dns (which should be setup already).

MY_DNS_NAME=<put_your_domain_here> # hello.test.acme.comsed -i "s/\$MY_DNS_NAME/$MY_DNS_NAME/" gce_ssl_ingress.yaml
kubectl create --filename gce_ssl_ingress.yaml

Verify Certificate is Available

This process can take a while from 10 to 20 minutes for the certificate to move from a Provisioning to an Active status.

Check with kubectl

You can verify the state of the certificate in Kubernetes with the following command:

kubectl describe \
Image for post
Image for post

Check with gcloud

You can also check with gcloud as well:

# SAN cert can have multiple domains, so newline as separator
# Format string with multi-line domain column
gcloud compute ssl-certificates list \
--filter "hello." \
--format "$FORMAT"
Image for post
Image for post

Test the Web Application

Once finished, you can use HTTPS to access the service, such as our example above

Image for post
Image for post


You can remove the deployed resources with the following command:

cat hello_*.yaml | kubectl delete --filename -

Notes on Google Managed SSL Certificates

The automation to create trusted certificates is great, but there are some things to consider then crafting your certificates:

  • no Wildcard certificates are supported, so you cannot register a certificate for * for example.
  • SAN (Subject Alternative Name) certificate can be used with Kubernetes 1.16 and above to allow multiple address, such as,,, and so on.
  • Every domain specific in the SAN certificate must be provisioned (ingress resource to create external load balancer and corresponding DNS record in Cloud DNS) or the certificate provisioning for all domains will never complete and certificates will not be available to secure traffic.

Managed SAN Certificate Behavior

On the requirement where domains specified in the SAN certificate must be used, this is not explicitly documented (at least in what I have researched) but I observed this behavior in y testing. Until all the certificated are attached to the external load balancer, they will remain in the status of PROVISIONING.

Reserved External IP Address

Deleting and recreating ingress resource is both disruptive and a time consuming process as a new ephemeral IP address will be created and DNS records pointing to the new address will have to be updated. For this reason, a reserved static external IP address is recommended.

ADDRESS_NAME=acme-address-name# create address
gcloud compute addresses create $ADDRESS_NAME --global
# retrieve the IP address
gcloud compute addresses describe $ADDRESS_NAME --global | \
awk '/^address:/{print $2}' acme-address-name


Blog Source Code

Google Documentation


This article is my fifth article in my new GKE series that shows you how to generally manage a stateless web applications with GKE flavor of Kubernetes.

Written by

Linux NinjaPants Automation Engineering Mutant — exploring DevOps, Kubernetes, CNI, IAC

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store