Multiple JWT and Validating

From Istio / Security

Request authentication policies can specify more than one JWT if each uses a unique location. When more than one policy matches a workload, Istio combines all rules as if they were specified as a single policy. This behavior is useful to program workloads to accept JWT from different providers. However, requests with more than one valid JWT are not supported because the output principal of such requests is undefined.

Is it intended to be read as “Istio allows multiple tokens but in an OR manner, not validating both”? Not sure I understand why a principal needs to be derived from the token and the documentation doesn’t explain how a service principal is used in executing AuthorizationPolicies, just that it’s used in telemetery. Which particular value is used as principle? Shouldn’t the sub value be the principle? And in that case just take the sub value from the body of the last token listed in the jwtrules. RequestAuthorization seems very narrow in it’s implementation when all I really need is a way to validate that the JWT was not tampered.

My use case is, I need to send two JWT access tokens to a service and I need them both validated. The reason i need two tokens is that I need additional claims provided from an internal API which provides additional RBAC rules and identity impersonation which my Identity Provider can’t fetch. If this can’t be done then I need to add additional token processing in the service.

Not sure I understand why a principal needs to be derived from the token … Which particular value is used as principle? Shouldn’t the sub value be the principle?

In this case we are talking about requestPrincipal, and you are correct, it is derived from a combination of the iss (or issuer) of the JWT and the sub (or subject, which is often a unique user id) like this example.com/12345. iss and sub are standard elements of a JWT, so they are used to derive the principal identity of the user bearing this token.

the documentation doesn’t explain how a service principal is used in executing AuthorizationPolicies

The docs are here, eg. you can create an AuthorizationPolicy which allows traffic only if the request principal is mytrustedissuer.com/* or something like that.

all I really need is a way to validate that the JWT was not tampered.

In that case you don’t need an AuthorizationPolicy. AuthorizationPolicy is used for making a decision about allowing / rejecting a request after the validity of the JWT has been established, which is handled by the RequestAuthentication CRD. However, without an AuthorizationPolicy like this one, requests that do not contain a valid JWT will be admitted into the cluster.

To be clear, merely validating JWT’s by way of a RequestAuthentication CRD is insufficient to require that all traffic has a valid JWT, you need to reject those requests that don’t have a JWT using that example I linked above.

Now, getting back to your use case…

I need to send two JWT access tokens to a service and I need them both validated.

You can do this by just adding another rule to the list of jwtRules on your RequestAuthentication resource as you discovered in the docs, you just need to specify which non-standard header the second bearer token can be found in.

However, I am not sure there’s a way to reject requests which do not have two valid JWT’s in them from two different issuers, because of this caveat:

requests with more than one valid JWT are not supported because the output principal of such requests is undefined

Which makes sense, if you have a token issued from foo.com for subject 123 and one from bar.com for subject 456, what would the requestPrincipal look like? foo.combar.com/123456 ? I don’t think there’s a way to express that requirement.

@rsalmond thanks for taking the time to reply.

To be clear, merely validating JWT’s by way of a RequestAuthentication CRD is insufficient to require that all traffic has a valid JWT, you need to reject those requests that don’t have a JWT using that example I linked above.

I really only need to reject the request if it has a forged JWT, otherwise no token at all would be considered a guest.

You can do this by just adding another rule to the list of jwtRules on your RequestAuthentication resource as you discovered in the docs, you just need to specify which non-standard header the second bearer token can be found in.

I’m going to give this a try and add another jwtRule but i’m afraid I do have an AuthorizationPolicy for the first token which might stop the route working.

Considering the request flow, the first token is needed in order to generate the second token so it could be implicit that the second token superceeds the first.

Some mechanism to imply the user principle based on the claims in the token(s) would be an awesome feature. Also a way to merge the non standard jwt claims together just validating iss/sub/aud/exp/nbf. If I trust both issuers just keep the list of jwt tokens a list and pick the last token as the implied user principle.