Microservice spike part 5 - SSL termination
This is part 5 in a series of posts where I spike out a cloud microservice app on GCP. In this post I secure the endpoint for my app by configuring it to use SSL / TLS (HTTPS).
- Part 1 - the CryptoTracker app introduces my prototype microservice app
- Part 2 - run in GCP gets the app running in Docker in Google Compute Engine
- Part 3 - run in GKE gets the app running in Google Kubernetes Engine
- Part 4 - run in an Istio service mesh gets the app running in an Istio service mesh
- Part 5 - secure the app via TLS (this page) secures the app by using TLS over HTTPS
Securing ingress
There is a great document on the isito site describing how to secure ingress with HTTPS which I followed in order to secure my app. It was simple enough to follow, but below are a few details that helped me. In a nutshell, the steps are:
- Configure istio listen for HTTPS traffic using a X.509 certificate and private key
- Forward that traffic on to my app via HTTP
Generate certificates and keys
The istio docs use a script to generate all the necessary public / private key pairs. The domain name I used to generate the certs was cryptotracker-demo.com
. This name is stamped into my certificates as the Common Name (CN). A client will access my app via a host name (eg. http://cryptotracker-demo.com/
) and will only trust my site if the server certificate’s CN matches the expected host name.
The istio server uses the application certificate which was signed by the intermediate. The client will have the intermediate public key and trust any certificates signed by it, so it should trust my app.
Create TLS secret
A kubernetes TLS secret will hold the public / private key pair for the application certificate. In order that the istio ingress gateway can read the secret it must be created in the correct istio-system
namespace. The k8s deployment manifest for the istio ingress gateway shows it maps the volume ingressgateway-certs
from a secret named istio-ingressgateway-certs
and mounts the certificates to /etc/istio/ingressgateway-certs
. They will be mounted as tls.crt
and tls.key
.
Create istio TLS gateway
This Gateway manifest instructs the isito ingress load balancer to listen on port 443. The tls
section instructs the gateway to use the public / private key pair that I injected earlier via a tls secret. The hosts
section is used during the TLS handshaking process: the client supplies the host name as a SNI value and istio will use it to match the client to the correct istio gateway.
As I did before, a VirtualService bridges traffic from the gateway to my app on HTTP port 80.
Test it
Following the istio docs I used curl
to test.
The Host
header and --resolve
parameters are used to supply the correct SNI value which will cause istio to match my request to my app. They are also used by curl
to verify that the server’s host name is correct, by matching against the certificate CN.
The intermediate certificate is used to verify the server’s identity. As described above, this is fine since the server’s certificate was signed by the intermediate.
It all works, but as a further test I used a new, blank, VM in a different GCP zone. Once I had created a basic VM I copied the intermediate certificate onto it by using SCP from the cloud shell:
I could then use the same curl
command to verify I could connect. In the real world one wouldn’t use self-signed certificates of course, my app would use a certificate signed by a trusted CA that is already known to my machine. I’d also have a DNS name so the Host
header and SNI value would be passed automatically.
cloud (15) k8s (4)