RequestAuthentication: JWT validation fails when auth header contains "Bearer: null"

Our setup includes a single instio-ingress installation with multiple gateways attached to it handling multiple domains, like:

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: admin
  namespace: default
  labels:
    app: admin
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 443
      name: https
      protocol: HTTPS
    tls:
      mode: SIMPLE
      credentialName: admin-tls
    hosts:
    - admin.example.com
  - port:
      number: 80
      name: http
      protocol: HTTP
    tls:
      httpsRedirect: true
    hosts:
    - admin.example.com
---
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: public
  namespace: default
  labels:
    app: public
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 443
      name: https
      protocol: HTTPS
    tls:
      mode: SIMPLE
      credentialName: public-tls
    hosts:
    - public.example.com
  - port:
      number: 80
      name: http
      protocol: HTTP
    tls:
      httpsRedirect: true
    hosts:
    - public.example.com

We would like to use request authentication for most of our applications living on specific domains, like:

apiVersion: security.istio.io/v1beta1
kind: RequestAuthentication
metadata:
  name: validate-jwt
  namespace: istio-system
spec:
  selector:
    matchLabels:
      istio: ingressgateway
  jwtRules:
  - issuer: "http://example.com/auth/realms/smaple"
    jwksUri: "http://example.com/auth/realms/smaple/protocol/openid-connect/certs"
    forwardOriginalToken: true
    outputPayloadToHeader: 'x-jwt-payload'

The following auth policy enables access for both domains:

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: "allow-access"
  namespace: istio-system
spec:
  selector:
    matchLabels:
      istio: ingressgateway
  action: ALLOW
  rules:
  - to:
    - operation:
        hosts: ["public.example.com", "admin.example.com"]

Everything is working like a charm, when:

  • the auth header contains a well-formed JWT
  • the auth header is not included within the request

The problem starts when the authorization header is included but contains a malformed payload, for e.g.:

curl 'https://public.example.com' \
  -H 'authorization: Bearer null' \
  --compressed
# Jwt is not in the form of Header.Payload.Signature with two dots and 3 sections

Unfortunately, I have no control over the UI which includes the invalid/malformed header.

How should I disable the JWT validation specifically for the domain public.example.com?

Or should I try to remove the auth header with an EnvoyFilter if the header contains Bearer: null?

Btw, running on istio@1.17.1.

Update

Headers

The following snippet can unify the auth headers by removing the ones violating the format of the JWT:

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: normalize-auth-header
  namespace: istio-system
spec:
  configPatches:
  - applyTo: HTTP_FILTER
    match:
      context: GATEWAY
      listener:
        filterChain:
          filter:
            name: "envoy.filters.network.http_connection_manager"
    patch:
      operation: INSERT_FIRST
      value:
        name: envoy.lua
        typed_config:
            "@type": "type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua"
            inlineCode: |
              function envoy_on_request(request_handle)
                if request_handle:headers():get("authorization") == "Bearer null" then
                  request_handle:headers():remove("authorization")
                end
              end

Disabling JWT validation for certain routes

I’ve tested the following snippet without luck in order to exclude the public.example.com from the JWT validation:

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: disable-jwt-validation
  namespace: istio-system
spec:
  workloadSelector:
    labels:
      istio: ingressgateway
  configPatches:
    - applyTo: HTTP_ROUTE
      match:
        context: GATEWAY
        routeConfiguration:
          vhost:
            name: public.example.com:443
      patch:
        operation: MERGE
        value:
          name: envoy.ext_authz_disabled
          typed_per_filter_config:
            envoy.ext_authz:
              "@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute
              disabled: true

Seemingly, the ingress got the config of the route, like:

    "typedPerFilterConfig": {
        "envoy.ext_authz": {
            "@type": "type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute",
            "disabled": true
        }
    }

but I’m still getting the error="invalid_token" response when the request includes its own auth token which is not compatible with the one verified by the RequestAuthentication resource.

Would you have any advice on the issue? Can I disable JWT verification/validation at all for certain domains?

My last hope is to have a separate istio-ingress workload where I can collect a manage those gateways, and domains that should not use JWT validation.

I think the authentication filter is the first in the filtering chain. If you want to override it, you must insert your filter before it. I don’t know if it is possible.

If the upstream sends you an invalid JWT and the authentication correctly handled it, what’s the harm to you? I think the log is very annoying.

Wouldn’t adding the requestPrincipals: ["*"] to your AuthorizationPolicy fix this?