Create an nginx-ingress load balancer in Kubernetes (GKE), with explicit allowlist (whitelist) of IPs

2 min read

Considering you already have a kubernetes cluster here we are going to use the kubernetes ingress-nginx helm chart to install nginx and serve a simple example app named status-app , once the load balancer is deployed we will use the IP to point a dns A record to it and finally add whitelist to only allow specific set of IPs or CIDR ranges and block everything else.

First, let's add the helm repo, pull and untar it locally:

helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm pull ingress-nginx/ingress-nginx --untar

Second, install the ingress-nginx chart which will create a load balancer/Ingress in your cluster, wait for it to be healthy:

helm install ingress-nginx -n ingress-nginx \
  ingress-nginx -f values/ingress-nginx/values.yaml\
  --create-namespace

Example in GCP for me it looks like this:

Now go to your DNS dashboard and add a wildcard (*), A record pointing to the IP used by the load balancer created by the nginx Ingress load balancer. Example in my case:

Deploy the sample status-app and it's kubernetes service:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: status-app
  namespace: default
  labels:
    app: status-app
spec:
  selector:
    matchLabels:
      app: status-app
  template:
    metadata:
      labels:
        app: status-app
    spec:
      containers:
        - name: nodejs-server-port-80
          image: cooervo/server-with-args:v1.0
          args: ["status app running 馃檪馃憤"]
          ports:
            - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: status-app
  namespace: default
  labels:
    app: status-app
spec:
  type: NodePort
  selector:
    app: status-app
  ports:
    - name: http
      port: 80 # this Service port (to receive connections externally)
      targetPort: 80 # the Pod port (to send connections to)

Finally, to allow external navigation into it you need to use a kubernetes Ingress notice spec.ingressClassName: nginx and the annotation with the IPs or CIDR ranges:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: status-app
  namespace: default
  annotations:
    nginx.ingress.kubernetes.io/whitelist-source-range: "120.0.200.127/32,100.0.0.2" # Add your IPs or CIDR ranges, here separated by commas
spec:
  ingressClassName: nginx
  rules:
    - host: status.cooervo.com
      http:
        paths:
          - pathType: Prefix
            backend:
              service:
                name: status-app
                port:
                  number: 80
            path: /

That's all, this has the advantage of configuring on the service/deployment level, which you can customize for each one of your kubernetes deployments.

If you try to visit the website from an IP that is not in whitelist-source-range annotation you'll get nginx's 403 Forbidden error screen.

I have created an example in github for easy reference.