kuberneteskubernetes-ingressistiodocker-for-mackube-proxy

IP Blacklisting in Istio


The IP whitelisting/blacklisting example explained here https://kubernetes.io/docs/tutorials/services/source-ip/ uses source.ip attribute. However, in kubernetes (kubernetes cluster running on docker-for-desktop) source.ip returns the IP of kube-proxy. A suggested workaround is to use request.headers["X-Real-IP"], however it doesn't seem to work and returns kube-proxy IP in docker-for-desktop in mac.

https://github.com/istio/istio/issues/7328 mentions this issue and states:

With a proxy that terminates the client connection and opens a new connection to your nodes/endpoints. In such cases the source IP will always be that of the cloud LB, not that of the client.

With a packet forwarder, such that requests from the client sent to the loadbalancer VIP end up at the node with the source IP of the client, not an intermediate proxy.

Loadbalancers in the first category must use an agreed upon protocol between the loadbalancer and backend to communicate the true client IP such as the HTTP X-FORWARDED-FOR header, or the proxy protocol.

Can someone please help how can we define a protocol to get the client IP from the loadbalancer?


Solution

  • Maybe your are confusing with kube-proxy and istio, by default Kubernetes uses kube-proxy but you can install istio that injects a new proxy per pod to control the traffic in both directions to the services inside the pod.

    With that said you can install istio on your cluster and enable it for only the services you need and apply a blacklisting using the istio mechanisms

    https://istio.io/docs/tasks/policy-enforcement/denial-and-list/

    To make a blacklist using the source IP we have to leave istio manage how to fetch the source IP address and use som configuration like this taken from the docs:

    apiVersion: config.istio.io/v1alpha2
    kind: handler
    metadata:
      name: whitelistip
    spec:
      compiledAdapter: listchecker
      params:
        # providerUrl: ordinarily black and white lists are maintained
        # externally and fetched asynchronously using the providerUrl.
        overrides: ["10.57.0.0/16"]  # overrides provide a static list
        blacklist: false
        entryType: IP_ADDRESSES
    ---
    apiVersion: config.istio.io/v1alpha2
    kind: instance
    metadata:
      name: sourceip
    spec:
      compiledTemplate: listentry
      params:
        value: source.ip | ip("0.0.0.0")
    ---
    apiVersion: config.istio.io/v1alpha2
    kind: rule
    metadata:
      name: checkip
    spec:
      match: source.labels["istio"] == "ingressgateway"
      actions:
      - handler: whitelistip
        instances: [ sourceip ]
    ---
    

    You can use the param providerURL to maintain an external list.

    Also check to use externalTrafficPolicy: Local on the ingress-gateway servce of istio.

    As per comments my last advice is to use a different ingress-controller to avoid the use of kube-proxy, my recomendation is to use the nginx-controller

    https://github.com/kubernetes/ingress-nginx

    You can configure this ingress as a regular nginx acting as a proxy