I am currently building an API based around a microservices architecture.
I am using JWT to authenticate users. I understand that when a user sends a login request a JWT containing the users identity and their roles/permissions etc is returned. This token is then sent with the users subsequent requests to tell the server who is sending the request. I think this is the correct understanding.
In a normal monolithic architecture this works well as explained. How can I transfer this to a microservices architecture to establish trust between microservices.
I could forward the users JWT to downstream microservices simply but this doesn't allow the downstream microservice to know who/which upstream microservice is sending the request.
An example would be I have a location microservice. I want to allow the restaurant microservice to make calls to the location microservice. But I also have a product microservice that I do not want to be able to call the location microservice.
Obviously I could just not code the product microservice to call the location microservice but this doesn't stop someone else from doing so.
Any suggestions?
You can make the communication between microservices secure atleast by following two methodologies :
JWt token : Let assume micro service A wants to communicate with micro service B, then the token issued by A and the audience of the token is B. In that case the token is signed by micro service A with its private key. The aud field in JWT will represents the audience, it can be a single service or a set of services. The value of aud parameter should be a pre agreed value between the services. In micro services you can use the regular expression to validate the audience. For example aud can be *.samplemicroservice.com. Audience service B can check whether token is intended for it or not by checking the aud field. Once confirmed it can use issuer's public key to verify it.
Mutual SSL : The straight forward way to achieve it is to use mutual ssl between services. Each service should have SSL enabled and should presents its certificate to the the other service and other service should check the validity of the certificate with a trust store. This should be validated at both microservice A and microservice B to reach a mutual agreement. A self signed certificate can be used as root CA for all services certificates and can be accessed through a trust store.
There can be many variations of these mechanism. Specifically in case of JWT token. For example, You can delegate the token issuing responsibility to one service and can validate token in each of the service using public key of issuer service.
Here you have two different problems to solve!
1) User authentication/authorization:
Yours downstream services services should pass the user JWT token to services upstream (dowstream depends on upstream, the downstream is more near of the frontend). This way all services can validate the JWT token, and we can garantee that the token is unchanged.
2) Micro services authorizarion:
This is the second scenario you have, you need to garantee the trust relation between microservices and the authorizations to access a resource. In this case, ever microservices do you have shoul be a client (act as user), in a auth service (key cloak, Authservice...) and before send a request to any upstream dependecy, it should be authenticated, and send his own JWT token, in this way the destination microserveice (the called one) can validate and alow or not alow the caller to access the resource, and later, check the end user credentials.
This kind of approuch can be achieved using the client credentias autorization flow (https://oauth.net/2/grant-types/client-credentials).
See this article: https://developer.okta.com/blog/2018/04/02/client-creds-with-spring-boot
I guess this solution to this should be that JWT should be passed to the gateway layer / Aggregator / Facade layer.
At this layer, just decode the JWT and set the data in the DTO(any Java Class), so that same is accessible easily.
Now, when this information needs to be passed to any service, these should be passed as params as anyhow API at the service layer should be generic.
Now if you want to establish trust b/w services, you can simply check the parameters as the services are anyhow should not be exposed outside apart from aggregators.
Hope I am making sense.
Related
I found one interesting article that has this illustration:
It says that:
API Gateway verifies access token for all incoming requests via introspection
But what does this mean?
it says that gateway goes to authorization server and validates token (JWT).
why is that needed?
if gateway has authorization server's public key, it can check token validity using signature just like every backend service, why is introspection needed and how is it done?
Depending on your Identity provider it can be done either way but there are trade offs.
If you validate the token locally then yes it can use public keys to do that and that's very efficient way, however downside is that if the token or signing keys are revoked then your token is still valid. With Remote check you have to bear the http overhead but that is more reliable.
Normally tokens are kept short lived and validated locally. But if your access token are long lived, your application require strict access controls or library doesn't support local validation then it's a good idea to check them remotely
I believe you are looking at this document.
What I understood from this Secure API Gateway is that the gateway is responsible for introspection and the back-end services will only check the token signature, which is less secure than introspection, but still a layer of security.
Introspection is necessary to validate the token information against the Authorization Server.
This is more secure, because the system can ensure that the token received is not malicious, expired and it is from an known source.
The details on how it is done are explained in RFC 7662.
Yes, the gateway could validate the token signature if it has access to the certificate.
I can't really tell why they choose the back-end server to do it, probably a project decision.
API Gateway primarily meant for routing the incoming calls to the corresponding MicroService Clusters.
In addition to that,it can also play a role to validate the token, so that only valid traffic is routed to the downstream servers (filtering malicious traffic).
The level of validation could be up to the product owner/architect decision. It could be as simple as validating against the list of in memory cached token or in depth validation on set of claims, digital signature verification, expiry time, audience claim etc.
You can view the set of claims inside the token using JWT decoder like https://devtoolzone.com/decoder/jwt
I am developing an app using microservices in NodeJS. I have built an auth api which handles the usual registration login etc and it issues JWT's
How do I use these to protect routes in a separate API microservice written with Express?
Do I need to use JWT with the secret to decrypt the token in the API app?
You could write a library that you import into your other microservices that requires all routes by default to require authentication. This library could have a mechanism to validate JWT's at the microservice level, so you never need to talk to your auth api to see if a JWT is valid or not. See the description and diagram below:
Your auth server will will need to be the single issuer of JWTs to your microservices. So, when a user logs in and successfully authenticates, your auth server will issue a JWT signed with a private key (signing MUST be asymmetric - RS256 is one example) you keep on the auth server only; do not give this private key to other microservices that you wish to validate JWTs inside of. What you can do is derive a public key based on the private key you sign your tokens with and publish that to an endpoint on your auth server that requires no authentication - the public key will be represented in the form of a JWK (see link to spec). Google does something similar here. Then, in each of your microservices, your library will need to devise a way to make a GET request to the public key endpoint on your auth server every X minutes to see if there are any changes and cache the public key in each microservice. By having the public key cached in your microservice, you will be able to validate the requesting JWT inside the service that is being requested.
Then whenever a request comes into one of your microservices, the library you import will examine the requesting JWT, check its validity, and grant access/authorization if the token is valid. The beauty of using a private/public key pair and asymmetric key signing is that you can validate a token based on the public key alone, but not sign it. So as long as each service has the public key from your /cert endpoint, they can validate a token without ever needing to talk to the auth server or knowing the private key.
This will require a little more work up front, but will yield you massive amount of ease, flexibility, and peace of mind in the future knowing only one source knows your private key.
One common pattern here would be to use an API gateway as the entry point to your entire microservice architecture. Incoming requests for authentication would be routed to the appropriate microservice. If the credentials provided be correct, a new JWT would be returned to the gateway, which would then forward to the caller. For the actual microservice APIs which comprise your application, the gateway would check that the incoming JWT be valid before allowing the request to hit the microservice.
This answer leaves out a few things, for simplicity. For instance, often you would want to have an authorization microservice, which decides what a user is allowed to do. Also, implementing JWT can be involved. You might need a cache layer to keep track of whitelisted and/or blacklisted JWT.
Here is the solution I came up with, to handle user data we can implement an Identity Provider Service (IDP) which is responsible for signing JWTs with symmetrical keys (rs256) and storing user information. The Identity Provider also has an open endpoint which will expose the public key in the form of a JWK (JSON Web Key) which is used to sign the JWT, This endpoint can be used to validate issued keys by any other service (ideally the external service would cache the JWK to reduce traffic to the IDP).
But This also poses another issue, that is we will have to implement more code to validate the tokens with the JWK endpoint. This is where an API Gateway comes in, The API gateway sits between the frontend client and the API server acting as a checkpoint. The API Gateway caches the JWK using the IDP endpoint and validates all the incoming requests. This means we would only have to implement features like JWK validation, rate-limiting, and SSL only to the API Gateway and we will not have to rely on the internal services for implementing these. Plus another improvement to the API Gateway would be to write the decoded JWT data onto the headers so the API Gateway can pass the decoded data for example: x-jwt-email: person#email.com directly to the internal services.
I found inspiration for this implementation from various sources and this was one of the first system designs that have completed building so let me know if there are any loopholes or improvements that could be implemented.
The code for the above implementation can be found here:
Identity Provider
API Gateway
I have multiple services:
User
Post
Comment
Authentication
GraphQL endpoint
And let's say they are connected together like this:
All services are communicating through gRPC on a closed nettwork and the Authorization is done using jwt tokens
Approach 1:
The graphql service is responsible for user authentication and making sure that the user is authorized to run the specified procedure. There is no user authentication between the services, but there is TLS authentication. There are no authorization checks done by the services.
Approach 2:
Each individual service makes sure that the user is authorized to run a specific procedure. An example could be voting on a post where you would need to be signed in and have over 15 in reputation. Here it would be the Post service's responsibility to check whether the user is signed in or not (authenticated) and whether it's authorized to vote. This will result in large overhead since every procedure call needs to check user authentication and authorisation through the Auth service.
Is there a better approach that still preserves the security of approach 2, but creates a small overhead like approach 1?
-----Update-----
Approach 3:
Same as approach 2, but user authentication is only done in the GraphQL service using the Auth service. The authorization is done by checking metadata passed around. And there is TLS authentication between the services.
Let's consider a request that travels from the authenticated user to service A and on to service B. The JWT should be passed on each of these calls.
Both services would first authenticate the user which is simply done by validating the JWT. Then each service would extract all information necessary to authorize the user from the user, for example the sub claim. It would use this information to decide if the user is authorized with respect to the operation that the service shall perform on behalf of the user. Only after successful authorization would the service actually do anything.
This would not be overhead but necessary to allow service B to both authenticate and authorize the user. Not passing the JWT from sercice A to service B would make it impossible for service B to know anything about the user.
I have project with many micro services each one doing its job. One of them responsible for authentication and authorization. But its not clear how other services should check users permissions. Is there any mechanism to deal with this task?
One of the best approaches is the OAuth delegation protocol with JSON token JWT
Authentication in micro-services architecture
the user send his credentials to the OAuth server
The server Checks the user's information (from LDAP server for example), then gives him an access token
the user send his request with the access token to the API Gateway
the API Gateway extracts out the access_token from the request, then he will talks to the Token Exchange endpoint to validate it and then issues a JWT
this JWT That contains all the necessarily information about the user will be sent to the micro-service.
the micro-service also should verify the validity of the token by talking to the token exchange endpoint.
when the token is checked, the micro-service can start its job.
I think this link will be useful for you Securing Microservices
You said that this responsibility belongs to a microservice. So, the other microservices don't check permissions, they delegate.
If you use an API Gateway and the other microservices are not accessible from the outside then it calls the authentication/authorisation microservice before forwarding the request to the upstream microservice.
If you don't use an API Gateway then each microservice call the authentication/authorisation microservice before actually performing the action.
We are building a web application in microservices architecture.
We have a service that handles the authorization (i.e user's privileges, access credentials, roles etc...) and we are considering how to pass on these credentials in the system.
We have 2 option:
1. Sign those credentials in the gateway (auth and proxy service) using JWT and pass on all the information so every service could verify it (with its public key) and read the user's info.
2. Every service should make a request to the authorization service for querying the user's access on every action.
We are having difficulties on deciding which way is better in terms of high cohesion and loose coupling and of course making it easy for service development.
You have some other options: instead of reinventing the wheel, you can use an OAuth 2.0 identity provider/broker out of the box.
Keycloak is a free open source identity provider and broker that provides all these functionalities.
Auth0 is a managed commercial service that provides all these functionalities too.
And I'm sure there are many other services exist for OAuth 2.0 protocol.
As for your 2 options:
You can extend the JWT with your custom authorisation claims (roles or permissions) and since the JWT will be signed, then it is safe to assume the data is correct by your service. Give that the JWT is a short lived token that need to renew every few minutes.