Whitelist source IP address for one of the services

Requirement

We have multiple services deployed to a namespace. We want to restrict one of the services to be accessed by a specific client. All other services can be invoked from any client.

Some Facts

Istio Version 1.3.0
Kubernetes Version: v1.13.5
Cloud : Oracle Cloud Infrastructure

More Details

The external traffic policy for the cluster is set to Cluster - externalTrafficPolicy: Cluster. As documented [1] , we would want to leave it as cluster not change it to local.

From the doc -
externalTrafficPolicy denotes if this Service desires to route external traffic to node-local or cluster-wide endpoints. “Local” preserves the client source IP and avoids a second hop for LoadBalancer and Nodeport type services, but risks potentially imbalanced traffic spreading. “Cluster” obscures the client source IP and may cause a second hop to another node, but should have good overall load-spreading. +optional`

[1] - https://archive.istio.io/v1.3/docs/reference/config/istio.operator.v1alpha12.pb/#k8s-io-api-core-v1-ServiceSpec

Here is my deployment yamls -

apiVersion: apps/v1
kind: Deployment
metadata:
  name: adhello-deployment
  namespace: test-feed
spec:
  selector:
    matchLabels:
      app: adhello-deployment
  replicas: 1
  template:
    metadata:
      labels:
        app: adhello-deployment
    spec:
      containers:
      - name: adhello-deployment
        image: phx.ocir.io/test/ad/adhello:latest
        ports:
        - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: adhello-svc
  namespace: test-feed
  labels:
    app: adhello-svc
spec:
  type: NodePort
  selector:
    app: adhello-deployment
  ports:
  - port: 8080
    protocol: TCP
    targetPort: 8080
    name: http
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: adhello-vs
  namespace: test-feed
spec:
  hosts:
  - "*"
  gateways:
  - spectra-istio-config-gateway.istio-system.svc.cluster.local
  http:
  - corsPolicy:
      allowCredentials: true
      allowHeaders:
      - '*'
      allowMethods:
      - GET
      - HEAD
      - POST
      - PUT
      - DELETE
      - TRACE
      - OPTIONS
      - CONNECT
      - PATCH
      allowOrigin:
      - '*'
    match:
    - headers:
        product:
          exact: feed
      uri:
        prefix: /greet/
    route:
    - destination:
        host: adhello-svc.test-feed.svc.cluster.local
        port:
          number: 8080
---
apiVersion: config.istio.io/v1alpha2
kind: handler
metadata:
  name: adhello-whitelistip
  namespace: test-feed
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: adhello-sourceip
  namespace: test-feed
spec:
  compiledTemplate: listentry
  params:
    value: source.ip | ip("0.0.0.0")
---
apiVersion: config.istio.io/v1alpha2
kind: rule
metadata:
  name: adhello-checkip
  namespace: test-feed
spec:
  match: source.labels["istio"] == "ingressgateway"
  actions:
  - handler: adhello-whitelistip
    instances: [ adhello-sourceip ]
---

Question

Can someone suggest how to whitelist a specific IP for a specific service ?

Reviewed the following pages -

https://discuss.istio.io/t/ip-whitelisting-in-istio/3171
https://discuss.istio.io/t/ip-whitelisting-at-istio/4899
https://discuss.istio.io/t/whitelisting-blacklisting-ips/4300
https://discuss.istio.io/t/istio-ingress-ip-whitelisting/2670

Hi!

Unfortunately, it’s not possible to preserve client IP and also keep external load balancing at “cluster”. That’s just how k8s works. By default, traffic is load balanced between nodes, and so you will see a node IP as a client IP in some cases.

Do not that we are deprecating Mixer policies in version 1.5. Please refer to authorization policies, and specifically the field ipBlocks instead.

Thanks @kuat for the response.

With Authorization Policies in 1.5., do we still need to set externalTrafficPolicy: Local ? I assume Yes as you mentioned this is how K8s works.

Appreciate if you can confirm.

Yes, it still requires Local. The only work-around without it is to use some header like x-forwarded-for at the cloud ingress, and then writing a policy about that header.

Yes, it’s still needed, you can also take a preview at the new task here: https://preliminary.istio.io/docs/tasks/security/authorization/authz-ingress/

Thanks @kuat @YangminZhu