<p><strong>What I am trying to achieve:</strong> block all traffic to a service, containing the code to handle this within the same namespace as the service.</p>
<p><strong>Why:</strong> this is the first step in &quot;locking down&quot; a specific service to specific IPs/CIDRs</p>
<p>I have a primary ingress GW called <code>istio-ingressgateway</code> which works for services.</p>
<pre class="lang-yaml prettyprint-override"><code>$ kubectl describe gw istio-ingressgateway -n istio-system
Name:         istio-ingressgateway
Namespace:    istio-system
Labels:       operator.istio.io/component=IngressGateways
              operator.istio.io/managed=Reconcile
              operator.istio.io/version=1.5.5
              release=istio
Annotations:  API Version:  networking.istio.io/v1beta1
Kind:         Gateway
Metadata:
  Creation Timestamp:  2020-08-28T15:45:10Z
  Generation:          1
  Resource Version:    95438963
  Self Link:           /apis/networking.istio.io/v1beta1/namespaces/istio-system/gateways/istio-ingressgateway
  UID:                 ae5dd2d0-44a3-4c2b-a7ba-4b29c26fa0b9
Spec:
  Selector:
    App:    istio-ingressgateway
    Istio:  ingressgateway
  Servers:
    Hosts:
      *
    Port:
      Name:      http
      Number:    80
      Protocol:  HTTP
Events:          &lt;none&gt;
</code></pre>
<p>I also have another &quot;primary&quot; GW, the K8s ingress GW to support TLS (thought I'd include this, to be as explicit as possible)</p>
<pre class="lang-yaml prettyprint-override"><code>k describe gw istio-autogenerated-k8s-ingress -n istio-system
Name:         istio-autogenerated-k8s-ingress
Namespace:    istio-system
Labels:       app=istio-ingressgateway
              istio=ingressgateway
              operator.istio.io/component=IngressGateways
              operator.istio.io/managed=Reconcile
              operator.istio.io/version=1.5.5
              release=istio
Annotations:  API Version:  networking.istio.io/v1beta1
Kind:         Gateway
Metadata:
  Creation Timestamp:  2020-08-28T15:45:56Z
  Generation:          2
  Resource Version:    95439499
  Self Link:           /apis/networking.istio.io/v1beta1/namespaces/istio-system/gateways/istio-autogenerated-k8s-ingress
  UID:                 edd46c17-9975-4089-95ff-a2414d40954a
Spec:
  Selector:
    Istio:  ingressgateway
  Servers:
    Hosts:
      *
    Port:
      Name:      http
      Number:    80
      Protocol:  HTTP
    Hosts:
      *
    Port:
      Name:      https-default
      Number:    443
      Protocol:  HTTPS
    Tls:
      Credential Name:     ingress-cert
      Mode:                SIMPLE
      Private Key:         sds
      Server Certificate:  sds
Events:                    &lt;none&gt;
</code></pre>
<p>I want to be able to create another GW, in the namespace <code>x</code> and have an authorization policy attached to that GW.
If I create the authorization policy in the <code>istio-system</code> namespace, then it comes back with <code>RBAC: access denied</code> which is great - but that is for all services using the primary GW.</p>
<pre class="lang-yaml prettyprint-override"><code>apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: block-all
  namespace: istio-system
spec:
  selector:
    matchLabels:
      app: istio-ingressgateway
  action: DENY
  rules:
    - from:
        - source:
            ipBlocks: [&quot;0.0.0.0/0&quot;]
</code></pre>
<p>What I currently have does not work. Any pointers would be highly appreciated. The following are all created under the <code>x</code> namespace when applying the <code>kubectl apply -f files.yaml -n x</code></p>
<pre class="lang-yaml prettyprint-override"><code>apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  annotations:
      app: x-ingress
  name: x-gw
  labels:
    app: x-ingress
spec:
  selector:
    istio: ingressgateway
  servers:
    - hosts:
        - x.y.com
      port:
        name: http
        number: 80
        protocol: HTTP
      tls:
        httpsRedirect: true
    - hosts:
        - x.y.com
      port:
        name: https
        number: 443
        protocol: HTTPS
      tls:
        mode: SIMPLE
        privateKey: sds
        serverCertificate: sds
        credentialName: ingress-cert
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: x
  labels:
    app: x
spec:
  hosts:
    - x.y.com
  gateways:
    - x-gw
  http:
    - route:
        - destination:
            host: x
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: x-ingress-policy
spec:
  selector:
    matchLabels:
      app: x-ingress
  action: DENY
  rules:
    - from:
        - source:
            ipBlocks: [&quot;0.0.0.0/0&quot;]
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: x
  labels:
    app: x
spec:
  hosts:
    - x.y.com
  gateways:
    - x-gw
  http:
    - route:
        - destination:
            host: x

</code></pre>
<p>The above should be blocking all traffic to the GW, as it matches on the CIDR range of <code>0.0.0.0/0</code></p>
<p>I am entirely misunderstanding the concept of GWs/AuthorizationPolicies or have I missed something?</p>
<p><strong>Edit</strong>
I ended up creating another GW which had the IP restriction block on that, as classic load balancers on AWS do not support IP forwarding.</p>
<pre class="lang-yaml prettyprint-override"><code>apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
  namespace: istio-system
  name: istiocontrolplane
spec:
  profile: demo
  components:
    ingressGateways:
      - name: istio-ingressgateway
        enabled: true
      - name: admin-ingressgateway
        enabled: true
        label:
          istio: admin-ingressgateway
        k8s:
          serviceAnnotations:
            service.beta.kubernetes.io/aws-load-balancer-type: &quot;nlb&quot;
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: deny-all-admin
  namespace: istio-system
spec:
  selector:
    matchLabels:
      istio: admin-ingressgateway
  action: ALLOW
  rules:
    - from:
        - source:
            ipBlocks: [&quot;176.252.114.59/32&quot;]
</code></pre>
<pre class="lang-sh prettyprint-override"><code>kubectl patch svc istio-ingressgateway -n istio-system -p '{&quot;spec&quot;:{&quot;externalTrafficPolicy&quot;:&quot;Local&quot;}}'
</code></pre>
<p>I then used that gateway in my workload that I wanted to lock down.</p>

<p>As far as I know you should rather use <a href="https://istio.io/latest/docs/reference/config/security/authorization-policy/" rel="noreferrer">AuthorizationPolicy</a> in 3 ways</p>
<ul>
<li>on ingress gateway</li>
<li>on namespace</li>
<li>on specific service</li>
</ul>
<p>I have tried to make it work on a specific gateway with annotations like you did, but I couldn't make it work for me.</p>
<p>e.g.</p>
<p>the following authorization policy denies all requests to workloads in namespace x.</p>
<pre><code>apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
 name: deny-all
 namespace: x
spec:
  {}
</code></pre>
<p>the following authorization policy denies all requests on ingress gateway.</p>
<pre><code>apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: deny-all
  namespace: istio-system
spec:
  selector:
    matchLabels:
      app: istio-ingressgateway
</code></pre>
<p>the following authorization policy denies all requests on <a href="https://raw.githubusercontent.com/istio/istio/release-1.7/samples/httpbin/httpbin.yaml" rel="noreferrer">httpbin</a> in x namespace.</p>
<pre><code>apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: deny-service-x
  namespace: x
spec:
  selector:
    matchLabels:
      app: httpbin
</code></pre>
<hr />
<p>Let's say you deny all requests on x namespace and allow only get requests for httpbin service.</p>
<p>Then you would use this AuthorizationPolicy to deny all requests</p>
<pre><code>apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: deny-all
  namespace: x
spec:
  {}
</code></pre>
<p>And this AuthorizationPolicy to allow only get requests.</p>
<pre><code>apiVersion: &quot;security.istio.io/v1beta1&quot;
kind: &quot;AuthorizationPolicy&quot;
metadata:
  name: &quot;x-viewer&quot;
  namespace: x
spec:
  selector:
    matchLabels:
      app: httpbin
  rules:
  - to:
    - operation:
        methods: [&quot;GET&quot;]
</code></pre>
<hr />
<p>And there is the main issue ,which is ipBlocks. There is related <a href="https://github.com/istio/istio/issues/22341" rel="noreferrer">github issue</a> about that.</p>
<p>As mentioned here by @incfly</p>
<blockquote>
<p>I guess the reason why it’s stop working when in non ingress pod is because the sourceIP attribute will not be the real client IP then.</p>
<p>According to <a href="https://github.com/istio/istio/issues/22341" rel="noreferrer">https://github.com/istio/istio/issues/22341</a> 7, (not done yet) this aims at providing better support without setting k8s externalTrafficPolicy to local, and supports CIDR range as well.</p>
</blockquote>
<hr />
<p>I have tried this example from <a href="https://istio.io/latest/docs/tasks/security/authorization/authz-ingress/" rel="noreferrer">istio documentation</a> to make it work, but it wasn't working for me, even if I changed <code>externalTrafficPolicy</code>. Then a workaround with <a href="https://istio.io/latest/docs/reference/config/networking/envoy-filter/" rel="noreferrer">envoyfilter</a> came from above istio discuss thread.</p>
<p>Answer provided by @hleal18 <a href="https://discuss.istio.io/t/authorization-policy-ip-allow-deny-not-working-on-services-different-than-ingress-gateway/7845/4?u=pikapika" rel="noreferrer">here</a>.</p>
<blockquote>
<p>Got and example working successfully using EnvoyFilters, specifically with remote_ip condition applied on httbin.</p>
<p>Sharing the manifest for reference.</p>
</blockquote>
<pre><code>apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: httpbin
  namespace: foo
spec:
  workloadSelector:
    labels:
      app: httpbin
  configPatches:
    - applyTo: HTTP_FILTER
      match:
        context: SIDECAR_INBOUND
        listener:
          filterChain:
            filter:
              name: &quot;envoy.http_connection_manager&quot;
              subFilter:
                name: &quot;envoy.router&quot;
      patch:
        operation: INSERT_BEFORE
        value:
          name: envoy.filters.http.rbac 
          config:
            rules:
              action: ALLOW
              policies:
                &quot;ip-premissions&quot;:
                  permissions:
                    - any: true
                  principals:
                    - remote_ip:
                        address_prefix: xxx.xxx.xx.xx
                        prefix_len: 32
</code></pre>
<hr />
<p>I have tried above envoy filter on my test cluster and as far as I can see it's working.</p>
<p>Take a look at below steps I made.</p>
<p>1.I have changed the externalTrafficPolicy with</p>
<pre><code>kubectl patch svc istio-ingressgateway -n istio-system -p '{&quot;spec&quot;:{&quot;externalTrafficPolicy&quot;:&quot;Local&quot;}}'
</code></pre>
<p>2.I have created namespace x with istio-injection enabled and deployed httpbin here.</p>
<pre><code>kubectl create namespace x
kubectl label namespace x istio-injection=enabled
kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.7/samples/httpbin/httpbin.yaml -n x
kubectl apply -f https://github.com/istio/istio/blob/master/samples/httpbin/httpbin-gateway.yaml -n x
</code></pre>
<p>3.I have created envoyfilter</p>
<pre><code>apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: httpbin
  namespace: x
spec:
  workloadSelector:
    labels:
      app: httpbin
  configPatches:
    - applyTo: HTTP_FILTER
      match:
        context: SIDECAR_INBOUND
        listener:
          filterChain:
            filter:
              name: &quot;envoy.http_connection_manager&quot;
              subFilter:
                name: &quot;envoy.router&quot;
      patch:
        operation: INSERT_BEFORE
        value:
          name: envoy.filters.http.rbac
          config:
            rules:
              action: ALLOW
              policies:
                &quot;ip-premissions&quot;:
                  permissions:
                    - any: true
                  principals:
                    - remote_ip:
                        address_prefix: xx.xx.xx.xx
                        prefix_len: 32
</code></pre>
<p><strong>address_prefix</strong> is the <strong>CLIENT_IP</strong>, there are commands I have used to get it.</p>
<pre><code>export INGRESS_HOST=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name==&quot;http2&quot;)].port}')
curl &quot;$INGRESS_HOST&quot;:&quot;$INGRESS_PORT&quot;/headers -s -o /dev/null -w &quot;%{http_code}\n&quot;
CLIENT_IP=$(curl &quot;$INGRESS_HOST&quot;:&quot;$INGRESS_PORT&quot;/ip -s | grep &quot;origin&quot; | cut -d'&quot;' -f 4) &amp;&amp; echo &quot;$CLIENT_IP&quot;
</code></pre>
<p>4.I have test it with curl and my browser.</p>
<pre><code>curl &quot;$INGRESS_HOST&quot;:&quot;$INGRESS_PORT&quot;/headers -s -o /dev/null -w &quot;%{http_code}\n&quot;
200
</code></pre>
<p><a href="https://i.stack.imgur.com/F18z9.png" rel="noreferrer"><img src="https://i.stack.imgur.com/F18z9.png" alt="enter image description here" /></a></p>
<hr />
<p>Let me know if you have any more questions, I might be able to help.</p>
