Question

I am rearchitecturing and rewriting my monolithic BaaS solution into microservices regarding to scalability and single responsibility rules. Due to the internal dependencies, services are placed on different logical tiers. See figure below;

enter image description here

Instead of directly accessing to database or key-value storage, each service in Tier 2 must use Tier 1 Data Storage Service. Target of the internal service calls are located via Configuration Service hosted independently from API Gateway. API Gateway is deployed and configured per product. Product has an apikey and apisecret.

Scenario 1:

  • End users can login to the hosted product. (http*://host/authentication/login)

Scenario 2:

  • Business Service serves a custom logic: MyClass.MyOperation() (http*://host/business/myclass/myoperation)
  • End users of Business Service must be authenticated via Authentication Service to use the business logic (token based authentication)

On monolithic architecture, I was able to intercept dispathced business invocations via configured interceptors inside current executing http task. Therefore I was able to receive AuthenticationToken from business service request and decide whether the end user has authenticated via authentication service by directly querying the key-value storage.

Following the micoservice architecture, before executing business logic Business Service should make a request with transferring all original request headers to the Authentication Service, awaits its response, then parse the authentication result, and executes desired business logic then pipes to the response task. Single responsibility, fair enough.

Question:

  • Considering each Tier 2 services can be distributed anywhere inside the network, what options do I have in order to safely distinguish the internal and external requests between gateway and microservices?
  • Would this approach could be used to prevent internal service loop?
Was it helpful?

Solution

The best thing to do is to ensure that all requests are from an authenticated source. This could mean a user request, but also a 'service' user that corresponds to each microservice. If a hacker gains access to your tier2, and you have an un-authenticated API, they can wreak havoc.

Each microservice should have its own distinct user for use for unsolicited requests, but generally every API call should be passing along the user token you received from the original request.

OTHER TIPS

Make sure you have some sort of context (for want of a better word) on all internal calls. This should contain an authentication token from the originator of any given request and can simply be passed on whenever you do internal requests.

You then need to perform authorization, based on the authentication token (ideally by verifying the token EVERY time), as appropriate within each micro-service.

For calls that are not due to an external user, make sure each one of your services acquires an appropriate authentication token, identifying it as the request originator.

Depending exactly on how your internal architecture looks, it may then be appropriate for a micro-service receiving a request identifying itself as the originator to result in an error.

The flow

Authorization, as horizontal concern, could be managed from API gateway. For each request, API gateway invokes authz service to decode authorization info (eg. jwt) or receives an error.

In case of succesful authorization, call the internal API. Since business microservices are at lower level of your architecture, they should never distinguish when an invocation is made from API Gateway or is an "internal call"

The context

Every time a client invokes a service, the system should retrieve its identity. In a distribuited environment this is cumbersome, but API gateway could use Authz service information (decoded claims in the jwt) to add a "context" to the forwarded service invocation.

The "context" is data that carries information about the distribuited transaction that has been started and its originator

Context propagation

In some scenario, microservices have to collaborate together to accomplish a transaction. In this case the calling service must forward context information to callee service. It could be useful to develop a library that does the job, saving context info (eg retrieved through http headers) along with request and add it to all outgoing requests. Is the same mechanism used to proapagte correlation Id...indeed, correlation Id represents a piece of the context!

Licensed under: CC-BY-SA with attribution
scroll top