Andrey Fedorov
Andrey Fedorov

Reputation: 9669

Limiting access by IP in kubernetes on GCP's GKE

I am running kubernetes (k8s) on top of Google Cloud Patform's Container Engine (GKE) and Load Balancers (GLB). I'd like to limit the access at a k8s ingress to an IP whitelist.

Is this something I can do in k8s or GLB directly, or will I need to run things via a proxy which does it for me?

Upvotes: 8

Views: 10504

Answers (7)

Vineeth
Vineeth

Reputation: 1032

To add to @rahul-sharma 's answer:

You can use BackendConfig CRD from GKE to bind the CloudArmour rules to the ingress service.

This was a pain to handle with terraform which I was trying for quite some time. With CRD, it is very easy.

# my-backendconfig.yaml
apiVersion: cloud.google.com/v1
kind: BackendConfig
metadata:
  name: my-backendconfig
spec:
  securityPolicy:
    name: "deny-access-policy" #cloud-armour policy name

and add these annotations to the service behind the Ingress

apiVersion: v1
kind: Service
metadata:
  name: my-api
  labels:
    app: my-app
  annotations:
    cloud.google.com/backend-config: '{"ports": {"80":"my-backendconfig"}}'
    cloud.google.com/neg: '{"ingress": true}'
spec:
  type: ClusterIP
  ports:
    - port: 80
      targetPort: api-http
      protocol: TCP
      name: api-http
  selector:
    app: my-app

Upvotes: 0

r4cc00n
r4cc00n

Reputation: 2117

I was looking into doing this and I found a fairly easy way to do it, assuming your service is of type: LoadBalancer, all you need to do nowadays is to add the following field to the spec definition.

loadBalancerSourceRanges:
    - x.x.x.x/32

You can add as many sources cidr's as needed, in case you are curious this is translated to a firewall rule that allows traffic from those sources, you can find the rule in the network that your service is using.

Upvotes: 1

vjdhama
vjdhama

Reputation: 5058

The way to whitelist source IP's in nginx-ingress is using below annotation.

ingress.kubernetes.io/whitelist-source-range

But unfortunately, Google Cloud Load Balancer does not have support for it, AFAIK.

If you're using nginx ingress controller you can use it.

The value of the annotation can be comma separated CIDR ranges.

More on whitelist annotations.

Issue tracker for progress on Google Cloud Load Balancer support for whitelisting source IP's.

Upvotes: 6

Rahul Sharma
Rahul Sharma

Reputation: 857

You can use Cloud Armor, Add a Policy, create your Allow/Deny Rules, then simply attach k8s LB in the target.

enter image description here

enter image description here

Upvotes: 4

Roberto Rios
Roberto Rios

Reputation: 39

You could use CORS and only allow the IP from the frontend to hit your microservices.

Upvotes: 0

gdzcorp
gdzcorp

Reputation: 73

Nowadays you can use nginx.ingress.kubernetes.io/whitelist-source-range as specified here: https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#whitelist-source-range

You need to be sure that you are forwarding external IPs to your services - https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip

And if you are using NGINX Ingress, make sure you set externalTrafficPolicy: Local on your ingress controllers service.

Upvotes: 2

Rishav Verma
Rishav Verma

Reputation: 11

GCP’s firewall rules cannot be applied on the Global Load Balancer it attaches with an Ingress that is created on GKE. If you want to restrict access to only specific IP addresses (for example : users connecting via VPN, in this case the VPN gateway’s IP address) then there is no out of the box solution on GCP, especially GKE.

Nginx and Http header “x-forwarded-for” to the rescue

If you are using GKE, chances are that you have a Microservices architecture and you are using an API Gateway, chances are that Nginx is the API Gateway. All that needs to be done is to configure nginx to only allow requests that have the following IPs

user.ext.static.ip → Public IP of the client

app.global.static.ip → Global static IP assigned to Ingress

nginx conf

location /my_service {
  rewrite_by_lua_file validate_ip.lua;
  proxy_pass http://my_service
}

validate_ip.lua

local cjson = require "cjson"

local status=""

local headers=ngx.req.get_headers()

local source_ips=headers["x-forwarded-for"]

if source_ips ~= "111.222.333.444, 555.666.777.888" then
  status="NOT_ALLOWED"
end

if status ~= "" then
  ngx.status = ngx.HTTP_UNAUTHORIZED
  ngx.header.content_type = "application/json; charset=utf-8"
  ngx.say(cjson.encode({ status = "ERROR",message=status.."YOUR_MESSAGE" }))
  return ngx.exit(ngx.HTTP_UNAUTHORIZED)
end

For more details read here

Upvotes: 0

Related Questions