Better practice... Google TLS ingress to non-encrypted backend vs. TLS to Dgraph

Hi all -

I’m in the process of moving our graph solution from neo4j to DGraph. We intend to run this on GKE and have a test environment running now. The next bit on my todo list is to put together a strategy for securing the graphql endpoint and Dgraph nodes. I’m running a HA configuration with 3 alphas and 3 zeros. Only the alpha service has a loadbalancer service type.

So… my question is. Which is better practice. Two enable TLS in Dgraph or to enable an ingress service that has TLS and leave Dgraph as is? Or is there an even better option?

The data will have some minor PII, so need to make sure security is tight.

@tommo Hello Tom.

With K8S you can of course have the TLS terminated at the endpoint, rather than have dgraph itself do this, and also get the benefit of using a trusted cert. However, in particular, on Google Cloud, you cannot do this with the service type of LoadBalancer alone. The reason is that Google Cloud does not support Layer 7 HTTP/S with service type of LoadBalancer.

For this, you will need to use an ingress, such as the default ingress gce or install an alternative, such as ingress-nginx.

In the case of default gce ingress, GKE will use an L7 load balancer, which can terminate TLS. Note that with the gce ingress, service can only be NodePort or LoadBalancer types. In the ingress-nginx case, this uses service LoadBalancer type (Layer 3/4 TCP) but then adds an nginx (openresty flavor) reverse-proxy to implement the ingress controller. Either way works fine.

For certificates, you have some options, you can use the built-in Google Managed SSL certificate (SAN certs) with gce ingress or use cert-manager Kubernetes add-on with something like ACME Let’s Encrypt for any ingress.

One nice thing about Google Managed SSL certificate is that there’s a CRD ManagedCertificate on GKE, which automates the provisioning the cert at the time a gce ingress is created (or rather creates the L7 load balancer outside of K8S) in the background. For the general usage around Google Managed SSL certificate, I recommend this blog (especially as I wrote it):

(Note: If medium puts up some paywall stuff, let me know, I can send you a friend link to bypass that)

Also, for deploying on dgraph on Kubernetes, we have a helm chart that you can use that supports adding ingress resources for alpha and ratel that might be useful:

2 Likes

So… I think I have it mostly set up. I have an ingress created. If I go to the http version of the ingress, I can get to graphql, but I get an SSL mismatch if I try to access the ingress via https. I have google managed cert. All that is fine. Do I need to apply a cert to the Dgraph service itself? If so, using the same cert as the ingress or the built in Dgraph cert?

The Google SSL cert is created at the moment the ingress is created. It could take 5+ minutes. Once the SSL is applied, you have to access it from HTTPS, as HTTP would fail. If you used alpha encryption on top of this, I would not even know how that would work, as it would be HTTPS within HTTPS…

When it does work, you chould be able to then access ratel (if you setup ratel in the ingress), e.g. https://ratel.mycompany.com. You could access alpha with curl, e.g.

curl https://alpha.mycompany.com/health
curl https://alpha.mycompany.com/state

If these fail then either the ingress setup is not working, dns not working, or ssl/tls is not working. If you like, you can send me helm chart values (redact any secrets) and the managed certificates manifest.

For troubleshooting managed google ssl cert, here’s some pointers. You can check the status of the certficate with this (replacing $MANAGED_CERT_NAME with named you used in metadata.name for ManagedCertificate):

MANAGED_CERT_NAME="<metadata.name-used-in-managed-cert>"
kubectl describe \
  managedcertificates.networking.gke.io/$MANAGED_CERT_NAME

It should say Active for the certificate, under the Status: > Domain Status: > Status:.

You can also use gcloud command to verify as well (replacing DNS_NAME with what you use to access the ingress):

DNS_NAME="<dns-name-of-system>" # if ratel.mycompany.com, then ratel.
DOMAINS_COL="managed.domains[].list(separator="$'\n'")"
FORMAT="table[box](name,type,managed.status,$DOMAINS_COL)"

gcloud compute ssl-certificates list \
 --filter "$DNS_NAME." \
 --format "$FORMAT"

This should show TYPE of MANAGED and MANAGED_STATUS of ACTIVE.