istio: Istio allows to break Kubernetes Namespace isolation when using `Ingress Gateway` and `VirtualService`

Describe the bug In order to enforce Namespace isolation, Kubernetes Ingress resource only allows references to Services in the same Namespace.

In contrast, with Istio it’s possible to create a VirtualService resource that references a Service from another Namespace and expose that Service to the outside world via Ingress Gateway.

Expected behavior Istio should consistently enforce Kubernetes Namespace isolation.

Steps to reproduce the bug

Use 3 namespaces:

  1. namespace-a - a namespace owned by “Istio Operator”, where a cluster-wide Istio Ingress Gateway is defined
  2. namespace-b - a namespace owned by “Team #1”, where httpbin sample application is deployed
  3. namespace-c - a namespace owned by “Team #2”, where Istio VirtualService resource is abused to expose to the outside world httpbin service owned by “Team #1
---
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: shared-gateway
  namespace: namespace-a
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    # one Gateway for all services
    - "*"
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: httpbin
  name: httpbin
  namespace: namespace-b
spec:
  ports:
  - name: http
    port: 8000
    protocol: TCP
    targetPort: 8000
  selector:
    app: httpbin
  sessionAffinity: None
  type: ClusterIP
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: httpbin
  namespace: namespace-c
spec:
  hosts:
  - "httbin-c.example.org"
  gateways:
  - shared-gateway.namespace-a.svc.cluster.local
  http:
  - match:
    - uri:
        prefix: /
    route:
    - destination:
        port:
          number: 8000
        # Notice: here we intentionally expose a service from somebody's else namespace !!!
        host: httpbin.namespace-b.svc.cluster.local

Version istioctl version:

Version: 1.0.1
GitRevision: 42773aacced474d97159902d20579a25b1f98106
User: root@832d5020b1d4
Hub: gcr.io/istio-release
GolangVersion: go1.10.1
BuildStatus: Clean

kubectl version:

Client Version: version.Info{Major:"1", Minor:"10", GitVersion:"v1.10.0", GitCommit:"fc32d2f3698e36b93322a3465f63a14e9f0eaead", GitTreeState:"clean", BuildDate:"2018-03-27T00:13:02Z", GoVersion:"go1.9.4", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"10+", GitVersion:"v1.10.6-gke.2", GitCommit:"384b4eaa132ca9a295fcb3e5dfc74062b257e7df", GitTreeState:"clean", BuildDate:"2018-08-15T00:10:14Z", GoVersion:"go1.9.3b4", Compiler:"gc", Platform:"linux/amd64"}

Is Istio Auth enabled or not? Yes

Environment GKE

Cluster state istio-dump.tar.gz

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 5
  • Comments: 18 (2 by maintainers)

Most upvoted comments

Hey stale bot, it is fixed? (:

Activity!

Is it accurate to say that, per the example provided, this breakdown of namespace isolation only occurs when the “foreign” service’s cluster FQDN is used? If so, I don’t see how this actually violates kubernetes namespace “isolation”, which AFAIK isolates short domain names by namespace, but allows communicating with services across namespaces using the cluster FQDN. Likewise, the “foreign” gateway reference uses the cluster FQDN.

Unless it can be demonstrated that namespace isolation is broken in the case of using references to the short service domain, I think this issue could be deemed invalid; if I’m missing something here, perhaps @yskopets could clarify. The only part of the observed behavior that I found unexpected was referencing the gateway as a service (by it’s FQDN), but that’s really just implementation details leaking through rather than unexpected behavior.

I suppose the issue is that it breaks from Kubernetes namespace isolation specifically with respect to ingress – using native k8s ingress, couldn’t you just deploy a proxy service in your team’s namespace that crosses the namespace boundary? Wouldn’t that be a better analogy for an Istio VirtualService anyway?

activity occurs…

@mabushey Thanks a lot! It’s working now. Figured out that my issue was just missing “svc” in gateway’s FQDN

@sh777 Let’s figure this out… Try adding this:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all
spec:
  podSelector: {}
  ingress:
  - {}

Make sure you list the namespace in the routing rule, for example here it’s istio-system:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:           
  name: grafana                                        
spec:
  hosts:                                
  - "grafana.example.com"
  gateways:
  - elb-gateway      
  http:
  - match:
    - uri:     
        prefix: /  
    route:          
    - destination:
        port:  
          number: 3000
        host: grafana.istio-system.svc.cluster.local

Also, make sure that your namespace has the sidecar or routing will not work:

kind: Namespace
apiVersion: v1
metadata:
  name: wordpress 
  labels:
    env: prd
    istio-injection: enabled

Hi @yskopets 😃

Your config does not transverse namespaces. I changed the httbin-c.example.org to a name that’s valid for my AWS LoadBalancer. In the browser I get “upstream connect error or disconnect/reset before headers” Which is what I get 100% of the time attempting to access a pod in a namespace that is not default when using a namespace for the VirtualService that is not default. I upgraded from Istio 1.0.1 to 1.0.2 today but see no difference is how this works. VirtualServices only work with the default namespace.

I stripped out all namespaces, changed shared-gateway.namespace-a.svc.cluster.local to shared-gateway and httpbin.namespace-b.svc.cluster.local to httpbin.default.svc.cluster.local. httpbin comes right up in the browser now.