What is the best pattern to implement JWT authentication (mTls is not the option for us) between microservices for publicly exposed endpoints?
Say, there is a user registration endpoint that is unprotected obviously but in turn it will call some other internal microservices to setup user data and those endpoints are protected.
All is that coming to my head is just use self signed service JWT tokens (i.e. service account).. But are there any other modern alternatives?
Thanks in advance.
Related
I know one of API Gateway offers is to provide a security layer of any backend APIs. But how if the case is the backend has its own authentication already (let say api key, jwt or other)? What is the better approach / best practice:
Modify those backend APIs to become "plain API" (without any auth), so will rely only on API Gateway auth (OAuth2)
Keep the backend auth as it is, but then create a microservice that will act as wrapper API to handle that backend auth.
The goal is to prevent double authentication & give the same experience to the clients where they only need to pass 1 authentication which is by the API Gateway. Thank you!
I would keep the backend's API security. There is nothing wrong with having secured communication behind an API gateway. As a matter of fact, I recall this being a recommended approach.
To prevent double authentication, would it be a suggestion to define a public (unsecured) end-point on the API gateway to access the authentication end-point of the authentication server used by your backend services. The client receives the authentication token from that authentication server and the API gateway passes the token through to the API of your backend services.
Another possibility could be to authenticate towards the API gateway but let the API gateway use the same authentication server as your backend services. Some gateways allow you to forward the authentication to an authentication server somewhere outside of the API gateway.
Lets say I have 2 Microservices (customer and payment), both consume APIs of external system (e.g. Stripe).
API Authentication
Assume that before consuming any business API of Stripe, API Consumer (in my case Customer & Payment Service) has to first authentication itself using API Keys (AppId and secret).
Stripe provides access token which must be passed into HTTP header into subsequent API calls to Stripe.
below can be possible approaches,
Approach1
https://drive.google.com/file/d/1BGn-hiNwZT4u3BIBmEv-HkJC0w0dk5CB/view?usp=sharing
Approach2: https://drive.google.com/file/d/1JA1hFq7l7-4Ow3b32XNyb2co4tqxKZQ6/view?usp=sharing
Approach1
Multiple auth token though Stripe account is single (per service instance)
Each service to manage auth token expiration/renewal
Approach2
Single auth-token exists with all services.
dependency on auth service.
auth token expiration/renewal managed by single service (Auth Service)
would like know which should be best fit in Microservice architecture? Any other suggestion?
Approach 2 is slightly more scalable and maintainable if more services will require API access to external APIs.
However the correct implementation would be an egress gateway for all your external API calls.
If your going to spend the time to build an Auth service, you might as well go all the way and centralize your external API routing as well.
Benefits:
Single internal endpoint for external APIs, reduces duplication.
Handles all authn and authz with external APIs for your services.
Centralizes all logging, auditing, disaster recover, load balancing etc....
Most gateway products like kong can be used for egress as well.
I plan to use Kong in our project. I'm currently working on a POC to see how we can integrate it in our platform as the main API gateway. I also want to use the JWT plugin for authentication and authorisation. I know that all the API calls should go through the Kong gateway to be authenticated. Then, if the authentication is validated they can go to the API.
Clients ---> Kong gateway ----> Apis
The part that is not very clear in my mind is how the APIs and Kong fit together.
Imagine a scenario where a client try to call directly an API with a token (bypassing the Gateway). How can the API use Kong to validate this token ?
How does Kong authenticates the APIs (not the Client) ? In the examples I have seen so far, only the authentication of the clients is documented, not the authentication of the APIs that are "protected" by Kong.
When using kong as an API Gateway (or for that matter any gateway) we tend to put it at the point where external clients talk to your service. It is a means to discover the individual services. And kong can do good enough job to validate such request.
For the calls you make to other services from within your set of microservices, you may allow for the free passage by means of directly invoking the service. Challenge in that case will be how the services will discover each other. (One way is to rely on DNS entries. We used to do that but later moved to kubernetes and started using their service discovery), and restrict all the incoming traffic to a given service from outside world. So they can only get in via gateway (and thats where we have all the security)
The reason behind the above philosophy is that we trust the services we have created (This may or may not be true for you and if its not then you need to route all your traffic via an api gateway and consider your APIs as just another client and they need to get hold of access token to proceed further or may be have another service discovery for internal traffic)
Or you may write a custom plugin in kong that filters out all the traffic that originates from within your subnet and validates everything else.
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.
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.