3 min read

How to run an Internal Load Balancer with SSL on GKE

I’ve spent too much time on this problem, and I hope you don’t have to as well.

When you create an Ingress configuration on GKE, it automatically launches a Layer 7 load balancer with all the bells and whistles. It’s also easy to enable HTTPS and even use their own managed certificate service. All is well until you understand that it only supports external load balancers and, setting the allowed source addresses is not trivial (and not supported at the time of writing).

One recommendation that came up a few times is setting the serivce type to LoadBalancer, with an “Internal” annotation, istead of Ingress. There is a lot of conflicting information, and the official GKE documentation is not very helpful. Are these the only options?

  1. HTTPS with an External Load Balancer
  2. Internal Load Balancer with no SSL

The answer is, of course, no. There is a way to achieve it, and in hindsight it’s pretty straight forward.

My initial confusion started when I messed around with a few Helm Charts that all had an Ingress option built in them. Thanks for the great abstraction, I didn’t think about the Ingress controller itself and assumed that the all-mighty GKE service would take care of it. Once I stopped to think, the obvious answer was to run “my own” controller.

A few minutes later, and I had my service published to my internal network with a valid SSL certificate.

Using an Nginx Ingress Controller with an Internal Load Balancer

To save some time, for this post, I used the stable/nginx-ingress Chart. All you have to add to the values.yaml file is the load-balancer-type annotation:

controller:
  service:
    annotations:
      cloud.google.com/load-balancer-type: "Internal"
In my case, I also wanted to set the load balancer IP and set the source range that will be able to access the service. My very simple POC values.yaml for the stable/nginx-ingress Chart:

rbac.create: true
controller.publishService.enabled: true

controller:
  service:
    loadBalancerIP: 172:16.2.100
    loadBalancerSourceRanges:
      - 10.0.30.0/24
    annotations:
      cloud.google.com/load-balancer-type: "Internal"
 

Installing the chart

helm install --name nginx-ingress stable/nginx-ingress -f values.yaml
 

The next thing that you have to do is make sure you are using the correct ingress controller in your application’s Ingress config.

  annotations:
    kubernetes.io/ingress.class: nginx
 

You will also have to create the secret that will contain the SSL certificate:

kubectl create secret tls my-certificate-secret --cert mycert.crt --key mycert.key

Then specify it in the Ingress settings of the app:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  namespace: default
  labels:
    "app.kubernetes.io/name": 'myapp'
  annotations:
    kubernetes.io/ingress.class: nginx

  name: myapp
spec:
  rules:
  - http:
      paths:
      - backend:
          serviceName: myapp
          servicePort: 8080
    host: "myapp.mydomain.com"
  tls:
    - hosts:
      - myapp.mydomain.com
      secretName: my-certificate-secret
 

Once everything is set up, you should be able to access the app through the internal load balancer with https enabled.

➜  myapp git:(master) ✗ kubectl get ingress
NAME         HOSTS                   ADDRESS   PORTS     AGE
myapp   myapp.mydomain.com             80, 443   3d18h


➜  myapp git:(master) ✗ kubectl get svc
NAME                            TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)                      AGE
kubernetes                      ClusterIP      10.12.0.1      <none>        443/TCP                      5d23h
nginx-ingress-controller        LoadBalancer   10.12.7.29     172:16.2.100    80:32103/TCP,443:30799/TCP   3d19h
nginx-ingress-default-backend   ClusterIP      10.12.2.22    <none>        80/TCP                       3d19h
 

Things are moving fast in DevOps? FOMO is creeping in?

An email that dives deep into subjects that are all DevOps

    We won't send you spam. Unsubscribe at any time.
    Powered By ConvertKit