Passing Authorization headers automatically (JWT) between microservices

Hello,
We are implementing Istio in existing architecture, where inter service communication is not authorized via JWT tokens, authorization is made at system entry point (custom API GW component) after which headers are stripped.

I have tried with test configuration for Istio with request authentication and authorization policies placed on namespace/workload level.

Problem I am facing that downstream services are protected via own authorization policies which expect jwt claims, but in current ms implementation jwt is not propagated in service to service HTTP communication.

I would like to avoid changes in ms implementation (jwt propagation).

Is Istio capable of passing automatically Authorization headers in service mesh?

cc @YangminZhu for authorization policies.

Do you just want to forward the JWT payload to your application service? This can be done with the outputPayloadToHeader field in the request authentication policy: https://istio.io/latest/docs/reference/config/security/jwt/

Thanks for your reply! Yes, I would like to forward the jwt from Service1 -> Service2 -> Service3, so claims on each service authorization policy can be matched an ex: key: request.auth.claims[roles].

Following is proxy log from Service2 when being invoked by Service1:

[2020-11-24T14:11:56.985Z] “POST /users HTTP/1.1” 403 - “-” “-” 0 19 0 - “-” “axios/0.19.2” “5740bb3c-9d02-99d0-9aa0-99bf2c29b178” “system-administration:3000” “-” - - 10.4.0.154:3000 10.4.0.152:39644 outbound_.3000_._.system-administration.istiodev.svc.cluster.local -
2020-11-24T14:14:11.928862Z debug envoy jwt Called Filter : setDecoderFilterCallbacks
2020-11-24T14:14:11.929484Z debug envoy jwt Called Filter : decodeHeaders
2020-11-24T14:14:11.929557Z debug envoy jwt Prefix requirement ‘/’ matched.
2020-11-24T14:14:11.929590Z debug envoy jwt extract authorizationBearer
2020-11-24T14:14:11.929618Z debug envoy jwt origins-0: JWT authentication starts (allow_failed=false), tokens size=0
2020-11-24T14:14:11.929641Z debug envoy jwt origins-0: JWT token verification completed with: Jwt is missing

If outputPayloadToHeader is solution, what would be the value of the property?

Thanks.

Hi Dean! Just to confirm, you wanna do the following:

Ingress Gateway -> Service1 -> Service2 -> Service3

The JWT is provided to the Ingress Gateway in the Authorization header and you want to add that same header to your call to Service 2 and so on, right?

I don’t see how to do that automatically, since it would be very hard for Istio (or any other proxy) to correlate the incoming TCP Socket to the outgoing TCP Socket (i.e., to know they belong to the same http or grpc request). From Istio’s point of view, the outgoing socket could belong to any request received or even started by an internal job of your application. It also cannot determine which thread in your application was responsible for handling a specific request.

The outputPayloadToHeader is used so The Proxy can outputs the base64(jwt_json), for a successfully verified JWT received by the Proxy, to your application under a new Header of your choice (i.e. the value of outputPayloadToHeader itself).

You could, instead, build a client library for making requests from your service to another that is able to lookup the original request and bypass the header on every call you make (something like a session).

Hope this helps

Hi Leandro,

Thanks for your response! I am considering other option, to have authorization policies placed on Ingress Gateway resource, therefore I wouldn’t get 401 from downstream services. Currently I don’t see any flaw to this approach.

Is there a possibility to map selected claims to header values? Ex. request.auth.claims[user_id] => header.user_id

Thanks.

You’re very welcome!

One way I see to do this is to use outputPayloadToHeader and create a Filter (https://istio.io/latest/docs/reference/config/networking/envoy-filter/) to get the information on that header and better organize it. But, once again, when you get this Header on Service A and then call an new Service B, your application will have to provide this value in the request, so Service B has access to it to.

This may help: https://github.com/BarDweller/istio-content-based-routing/blob/1a42d1029e99e64084e30117cbf744a7dac51906/istio-envoy-filter-jwt-lua.yaml. But use the outputPayloadToHeader, so you can be sure that Istio has already validated the JWT you received.