Cannot get EnvoyFilter ext_authz to work

The idea is to use Istio (v1.6.1) authenticate a service (httpbin here) with an external IDP (Dex) via an OAuth proxy. For the sake of completeness I will put all the code here.

The filter seem to be intercepting on port 80 but the patch to ext.authz doesn’t seem to do anything. It just times out even though the service on the uri is up and accessible. The outbound cluster is also accessible and listed in the istio proxy of the httpbin pod.

Filter:

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: authn-filter
  namespace: istio-system
spec:
  workloadSelector:
    labels:
      app: httpbin
  configPatches:
  - applyTo: HTTP_FILTER
    match:
      context: SIDECAR_INBOUND
      listener:
        portNumber: 80
        filterChain:
          filter:
            name: "envoy.http_connection_manager"
            subFilter:
              name: "envoy.router"
    patch:
      operation: INSERT_BEFORE
      value:
        name: envoy.ext_authz
        typed_config:
          "@type": type.googleapis.com/envoy.config.filter.http.ext_authz.v2.ExtAuthz
          http_service:
            server_uri:
              uri: http://oauthproxy-service.default.svc.cluster.local
              cluster: outbound|4180||oauthproxy-service.default.svc.cluster.local:4180
              timeout: 3s

Other pieces:

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: httpbin-gateway
  namespace: foo
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "*"

---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: httpbin
  namespace: foo
spec:
  hosts:
  - "*"
  gateways:
  - httpbin-gateway
  http:
  - route:
    - destination:
        port:
          number: 8000
        host: httpbin.foo.svc.cluster.local

---

apiVersion: v1
kind: ServiceAccount
metadata:
  name: httpbin
  namespace: foo
---
apiVersion: v1
kind: Service
metadata:
  name: httpbin
  labels:
    app: httpbin
  namespace: foo
spec:
  ports:
  - name: http
    port: 8000
    targetPort: 80
  selector:
    app: httpbin
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpbin
spec:
  replicas: 1
  selector:
    matchLabels:
      app: httpbin
      version: v1
  template:
    metadata:
      labels:
        app: httpbin
        version: v1
    spec:
      serviceAccountName: httpbin
      containers:
      - image: docker.io/kennethreitz/httpbin
        imagePullPolicy: IfNotPresent
        name: httpbin
        ports:
        - containerPort: 80

--
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    k8s-app: oauth2-proxy
  name: oauth2-proxy
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      k8s-app: oauth2-proxy
  template:
    metadata:
      labels:
        k8s-app: oauth2-proxy
    spec:
      containers:
        - args:
            - --cookie-secure=false
            - --upstream=file://dev/null
            - --http-address=0.0.0.0:4180
            - --cookie-secret=changeme
            - --client-id=changeme
            - --client-secret=changeme
            - --email-domain="*"
            - --provider=oidc
            - --provider-display-name="Dex oidc"
            - --redirect-url=http://10.106.200.144:4180/oauth2/callback
            #following should match what is configured in dex
            - --oidc-issuer-url=http://192.168.64.1:5556/dex

          image: quay.io/pusher/oauth2_proxy:v5.1.1
          imagePullPolicy: Always
          name: oauth2-proxy
          ports:
            - containerPort: 4180
              protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
  labels:
    k8s-app: oauth2-proxy
  name: oauthproxy-service
  namespace: default
spec:
  ports:
    - name: http
      port: 4180
      protocol: TCP
      targetPort: 4180
  selector:
    k8s-app: oauth2-proxy

I can see in the forum few similar questions most of them with no final outcome. I am suspecting the viability of this solution using filters altogether.

this is the filter that eventually worked for me

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: authn-filter
  #namespace: istio-system
  namespace: foo
spec:
  workloadSelector:
    labels:
      app: httpbin
  configPatches:
  - applyTo: HTTP_FILTER
    match:
      context: SIDECAR_INBOUND
      listener:
        portNumber: 80
        filterChain:
          filter:
            name: "envoy.http_connection_manager"
            subFilter:
              name: "envoy.router"
    patch:
      operation: INSERT_BEFORE
      value:
        #name: envoy.filters.http.ext_authz
        name: envoy.ext_authz
        typed_config:
          "@type": type.googleapis.com/envoy.config.filter.http.ext_authz.v2.ExtAuthz
          http_service:
            server_uri:
              uri: http://oauthproxy-service.default.svc.cluster.local:4180
              cluster: outbound|4180||oauthproxy-service.default.svc.cluster.local
              timeout: 3s

            authorizationRequest:
              allowedHeaders:
                patterns:
                - exact: "cookie"
          
1 Like

I’m having some issues with getting this setup.

What I am trying to get done is use Istio + Dex + oauth2-proxy. Is this the latest configuration working for you?

Currently this is what I have configured.

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: authn-filter
  namespace: istio-system
spec:
  workloadSelector:
    labels:
      istio: ingressgateway
  configPatches:
    - applyTo: HTTP_FILTER
      match:
        context: GATEWAY
        listener:
          filterChain:
            filter:
              name: 'envoy.http_connection_manager'
              subFilter:
                name: 'envoy.router'
      patch:
        operation: INSERT_BEFORE
        values:
          name: 'envoy.filters.http.ext_authz'
          config:
            http_service:
              server_uri:
                uri: http://oauth2-proxy.network.svc.cluster.local
                cluster: outbound|80||oauth2-proxy.network.svc.cluster.local
                timeout: 10s
            authorization_request:
              allowed_headers:
                patterns:
                  - exact: 'cookie'

I don’t know what issues you’re facing but one header is not enough.
This worked for me before: https://github.com/rezagh/istio-auth

Thanks @Reza I applied your EnvoyFilter with the only adjustment being I changes the label and namespace to be the following:

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: authn-filter
  namespace: istio-system
spec:
  workloadSelector:
    labels:
      app: kiali
  configPatches:
    - applyTo: HTTP_FILTER
      match:
        context: SIDECAR_INBOUND
        #context: GATEWAY
        listener:
          portNumber: 80
          filterChain:
            filter:
              name: 'envoy.http_connection_manager'
              subFilter:
                name: 'envoy.router'
      patch:
        operation: INSERT_BEFORE
        value:
          #name: envoy.filters.http.ext_authz
          name: envoy.ext_authz
          typed_config:
            '@type': type.googleapis.com/envoy.config.filter.http.ext_authz.v2.ExtAuthz
            http_service:
              server_uri:
                uri: http://oauthproxy-service.default.svc.cluster.local:4180
                cluster: outbound|4180||oauthproxy-service.default.svc.cluster.local
                timeout: 3s

              authorizationRequest:
                allowedHeaders:
                  patterns:
                    - exact: 'cookie'
                    - exact: 'x-forwarded-access-token'
                    - exact: 'x-forwarded-user'
                    - exact: 'x-forwarded-email'
                    - exact: 'authorization'
                    - exact: 'x-forwarded-proto'
                    - exact: 'proxy-authorization'
                    - exact: 'user-agent'
                    - exact: 'x-forwarded-host'
                    - exact: 'from'
                    - exact: 'x-forwarded-for'
                    - exact: 'accept'
                    - prefix: 'x-forwarded'
                    - prefix: 'x-auth-request'
                    - prefix: _oauth2_proxy
                    - exact: cookie
              authorizationResponse:
                allowed_upstream_headers:
                  patterns:
                    - exact: authorization
                    - exact: Cookie
                    - exact: cookie
                    - prefix: x-forwarded
                    - prefix: x-auth-request
                    - prefix: _oauth2_proxy
                allowedClientHeaders:
                  patterns:
                    - exact: 'location'
                    - exact: 'proxy-authenticate'
                    - exact: 'set-cookie'
                    - exact: 'authorization'
                    - exact: 'www-authenticate'
                    - prefix: 'x-forwarded'
                    - prefix: 'x-auth-request'
                allowedUpstreamHeaders:
                  patterns:
                    - exact: 'location'
                    - exact: 'proxy-authenticate'
                    - exact: 'set-cookie'
                    - exact: 'authorization'
                    - exact: 'www-authenticate'
                    - prefix: 'x-forwarded'
                    - prefix: 'x-auth-request'

When I attempt to reach kiali.example.com I’m sent directly to the service, I would have expected to be routed to my oauth proxy?

so the filter is not picking it up? please double check port /label.
you can also look at the logs of the proxy in debug mode.
otherwise need to see your whole config of the service etc.

Kiali service:

apiVersion: v1
kind: Service
metadata:
  name: kiali
  namespace: istio-system
  labels:
    app: kiali
    install.operator.istio.io/owning-resource: istio
    install.operator.istio.io/owning-resource-namespace: istio-system
    operator.istio.io/component: AddonComponents
    release: istio
spec:
  clusterIP: 10.105.139.248
  ports:
  - name: http-kiali
    port: 20001
    protocol: TCP
    targetPort: 20001
  selector:
    app: kiali
  sessionAffinity: None
  type: ClusterIP

EnvoyFilter

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: authn-filter
  namespace: istio-system
spec:
  workloadSelector:
    labels:
      app: kiali
  configPatches:
    - applyTo: HTTP_FILTER
      match:
        context: SIDECAR_INBOUND
        #context: GATEWAY
        listener:
          portNumber: 20001
          filterChain:
            filter:
              name: 'envoy.http_connection_manager'
              subFilter:
                name: 'envoy.router'
      patch:
        operation: INSERT_BEFORE
        value:
          #name: envoy.filters.http.ext_authz
          name: envoy.ext_authz
          typed_config:
            '@type': type.googleapis.com/envoy.config.filter.http.ext_authz.v2.ExtAuthz
            http_service:
              server_uri:
                uri: http://oauth2-proxy.network.svc.cluster.local:80
                cluster: outbound|80||oauth2-proxy.network.svc.cluster.local
                timeout: 10s
              authorizationRequest:
                allowedHeaders:
                  patterns:
                    - exact: 'cookie'
                    - exact: 'x-forwarded-access-token'
                    - exact: 'x-forwarded-user'
                    - exact: 'x-forwarded-email'
                    - exact: 'authorization'
                    - exact: 'x-forwarded-proto'
                    - exact: 'proxy-authorization'
                    - exact: 'user-agent'
                    - exact: 'x-forwarded-host'
                    - exact: 'from'
                    - exact: 'x-forwarded-for'
                    - exact: 'accept'
                    - prefix: 'x-forwarded'
                    - prefix: 'x-auth-request'
                    - prefix: _oauth2_proxy
                    - exact: cookie
              authorizationResponse:
                allowed_upstream_headers:
                  patterns:
                    - exact: authorization
                    - exact: Cookie
                    - exact: cookie
                    - prefix: x-forwarded
                    - prefix: x-auth-request
                    - prefix: _oauth2_proxy
                allowedClientHeaders:
                  patterns:
                    - exact: 'location'
                    - exact: 'proxy-authenticate'
                    - exact: 'set-cookie'
                    - exact: 'authorization'
                    - exact: 'www-authenticate'
                    - prefix: 'x-forwarded'
                    - prefix: 'x-auth-request'
                allowedUpstreamHeaders:
                  patterns:
                    - exact: 'location'
                    - exact: 'proxy-authenticate'
                    - exact: 'set-cookie'
                    - exact: 'authorization'
                    - exact: 'www-authenticate'
                    - prefix: 'x-forwarded'
                    - prefix: 'x-auth-request'
❯ istioctl experimental authz check kiali-6fcb9f7c-t2p82
Checked 10/26 listeners with node IP 172.16.36.201.
LISTENER[FilterChain]     CERTIFICATE          mTLS (MODE)          AuthZ (RULES)
0.0.0.0_80[0]             none                 no (none)            no (none)
0.0.0.0_80[1]             none                 no (none)            no (none)
0.0.0.0_3030[0]           none                 no (none)            no (none)
0.0.0.0_3030[1]           none                 no (none)            no (none)
0.0.0.0_8383[0]           none                 no (none)            no (none)
0.0.0.0_8383[1]           none                 no (none)            no (none)
0.0.0.0_9411[0]           none                 no (none)            no (none)
0.0.0.0_9411[1]           none                 no (none)            no (none)
0.0.0.0_14250[0]          none                 no (none)            no (none)
0.0.0.0_14250[1]          none                 no (none)            no (none)
virtualOutbound           none                 no (none)            no (none)
virtualInbound[0]         noneSDS: default     yes (none)           no (none)
virtualInbound[1]         none                 no (none)            no (none)
virtualInbound[2]         noneSDS: default     yes (none)           no (none)
virtualInbound[3]         none                 no (none)            no (none)
virtualInbound[4]         none                 no (none)            no (none)
virtualInbound[5]         none                 no (none)            no (none)
virtualInbound[6]         noneSDS: default     yes (PERMISSIVE)     no (none)
virtualInbound[7]         none                 no (PERMISSIVE)      no (none)
0.0.0.0_15010[0]          none                 no (none)            no (none)
0.0.0.0_15010[1]          none                 no (none)            no (none)
0.0.0.0_15014[0]          none                 no (none)            no (none)
0.0.0.0_15014[1]          none                 no (none)            no (none)
0.0.0.0_20001[0]          none                 no (none)            no (none)
0.0.0.0_20001[1]          none                 no (none)            no (none)

After some further tweaking I’ve got it semi-working, just need to iron out the network flow between DEX and oauth2-proxy and I should be good!

1 Like

Thanks for sharing the example . I am also working on a similar feature but instead of applying the authz filter at sidecar i wanted to apply at gateway level. Is there any way by which i can route only specific requests to oauth proxy based on the path only instead of applying to all the requests .

In the example shared , as per understanding all incoming requests will routed to the oauth proxy ?

e.g. if we have two requests say /foo and /bar only requests /foo shall be redirected to oauth proxy .

this is now supported by using the CUSTOM action in authz policy, check the blog Istio / Better External Authorization for more details, you can put /foo in the authz policy for this purpose.

Can the path be added to a envoy filter