Microservice to Microservice calls, authorization from a queue message
Asked Answered
M

3

12

Context: I'm creating a cloud platform to support multiple applications with SSO. I'm using Keycloak for authentication and Netflix Zuul for authorization (API Gateway) thru Keycloak Spring Security Adapter.

Each microservice expect an Authorization header, which contains a valid JWT, from which it will take the username (sub) to process the request. Each microservice-to-microservice call should go thru Netflix Zuul first, passing the Authorization header to maintain a stateless validation. That strategy allow to every microservice to know who is the user (sub) who is invoking the microservice indirectly.

Problem/Question 1: What happens if a microservice is invoked from a queue message? One idea that I had is to storage in the queue the information related to the message + userInfo, and, create a dedicated microservice to process that kind of messages, with that approach this special microservice should read the userInfo from the queue and process the message.

UPDATE 1: Per an email reply from another forum, storing the JWT in a queue isn't a good idea, since it could be mined easily.

Problem/Question 2: But, what happens if the previous special microservice wants to call another normal microservice which expect to receive a JWT in a header? Should this special microservice create by himself a JWT to impersonate the user and be able to call the regular microservices?

Another solution that I thought was to storage the original JWT in the queue, but, what happens if the queue calls to the special microservice later? Just after the JWT is not valid anymore (it expired) and the microservice called will reject the request?

Possible solutions: (Updated per João Angelo discussion, see below)

I should authenticate the requests from my users (Authorization code flow) and my services (Client credentials grant), both requests should contain user information in the payload. When the request it comes from the user, I need to validate that the payload user info match with the JWT claims. When the request comes from a service, I just need to trust in that service (as long as it is under my control).

I will appreciate very much your help. Thanks.

Mvd answered 7/11, 2016 at 6:5 Comment(1)
"Per an email reply from another forum" - which forum, can you provide a link?Packthread
B
6

Disclaimer: I never used Keycloak, but the tag wiki says it's compliant with OAuth2 so I'll trust that information.


At a really high-level view, you seem to have two requirements:

  1. authenticate actions triggered by an end user while he's using your system.
  2. authenticate actions triggered by your system at an unknown time and where there is no requirement for a end-user to be online.

You already met the first one, by relying on a token-based authentication system and I would do exactly the same for the second point, the only difference would be that the tokens would be issued to your system using the OAuth2 client credentials grant instead of the other grants that are targeted at scenarios where there is an end-user.

Client Credentials Grant

(source: Client Credentials Grant)

In your case, Keycloak would play the role of Auth0 and your client applications are microservices which can maintain client secrets used to authenticate themselves in the authorization server and obtain access tokens.

One thing to have in mind is that if your system relies on the sub claim for much more than authentication and authorization then you may need to make some adjustments. For example, I've seen systems where performing action A required to know that it was targeted at user X and Y, but the payload for the action only received user Y and assumed user X was the current authenticated principal. This works fine when everything is synchronous, but by merely switching the payload to specify both users would mean that the action could be done asynchronously by a system authenticated principal.

Botheration answered 8/11, 2016 at 10:45 Comment(3)
Hello João, I understand, so, 1) the microservices should expect always a JWT either from User or another service. I just did the test, and found that some of the differences between a JWT for a microservice compared to an user doesn't contains claims, and it contains an additional "clientId" field so that, something like, if the JWT contains a "clientId" isn't a user but a service. Or, I can rely in the "aud" field, if the "aud" correspond to the Client name to authenticate users, it's an user, if not, is another service.Mvd
2) It seems that I need to send always the userId in the payload so that the service can process the requests in a transparent way (service or user call), if I identify that the call is from an user either "aud" or "clientId" I can verify the payload field with the "sub" or "preferred_username" to be sure that the value of the payload corresponds to the user that is doing the action. But, in the case of a service, I just need to trust in user that is specified in the payload?Mvd
Yes, that would be one approach, validate the input when it comes from the users to make sure they don't try to fake other users and trust it when it comes from your own services. Assuming all microservices are under your control this seems like a suitable approach. It also seems simpler than storing access tokens and/or refresh tokens so that you can later perform the call even if the user is offline.Grenadine
H
0

One common setup is to have an API gateway that verify all incoming requests by their JWT. The API Gateway validates the signature of the JWT (or decrypt it for encrypted JWT's), checks the the expiry time etc, and extract the scopes and the User ID (sub) from it.

It then compare the scopes with a set of defined scopes for each micrto service, and if the scope provides the user (subject) access, the request is forwarded to the micro service. The User ID (sub in the JWT), along with other needed information stored in the JWT is placed in custom requests headers like X-IGNACIO-SUBJECT

Hipbone answered 9/11, 2016 at 8:9 Comment(1)
The question was also about service to service communication. Since not every service in a cluster shouldn't be allowed to call another. So also your services need some authentication and authorization mechanism, for example policies like istio istio.io) does or using jwt for every service: stormpath.com/blog/microservices-jwt-spring-bootPupil
D
0

As you said your microservices use JWT for authentication which always passes through a gateway, in this way you can actually use the concept of FEIGN CLIENT. Feign as rest client example.

Dol answered 19/2, 2020 at 6:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.