We are trying to determine the best way to authorise users in a microservice architecture, while ensuring microservices have limited permissions. Our architecture uses a central authorisation service to handle issuing of JWT tokens.

We have the following requirements:

  1. Users should be limited to perform certain roles. e.g. a user should only be able to create/modify/read content that he owns.

  2. Microservices should be limited to only the permissions they require. e.g. a microservice that only needs to read data from another service should be explicitly forbidden from writing data to that service.

As an example, suppose we have a system where users can upload pictures to an image store service. We have a tagging service that automatically tags pictures with a location. Users can only CRUD their own pictures. The tagging service can read any image from the image store service, however should not be able to modify/delete.

What is a good way to achieve the above using JWT tokens? Some solutions that we've discussed are:

  1. The image store service expose 2 APIs, one that is available externally (giving user CRUD access), and one that is available internally (giving internal read-only access). Seems inflexible - what if another internal service needs read/write access to all images (e.g. one that automatically deletes explicit images)?

  2. We set up two permissions in the user's JWT, one being CRUD_OwnImages, the other being READ_ForAnalysis. The tagging service can see if the user has READ_ForAnalysis permissions, and if so, make the appropriate request. We have another microservice that checks to see if user has CRUD_OwnImages for CRUD operations on the user's own images. This puts the responsibility on each microservice to ensure that the user is restricted to the actions he requires. The image store has no way to restrict each microservice with this approach, so it is potentially flakey and error prone.

  3. We give the tagging microservice its own user, with READ_ForAnalysis as a permission. Then, when the tagging service requests images from the image store, it is given access to those, but is forbidden from modifying them. The user's user only has CRUD_OwnImages permission, so he is able to retrieve and get access to only his images from the frontend. If another service needs CRUD to all data, we can give it CRUD_AllData or similar. We like this approach as each service is now responsible for its own data (rather than that logic being duplicated across multiple services), but what if the service requires both user permissions and microservice permissions? Can we send two JWT tokens (both the user's and the microservice's) securely? Is there a way to combine permissions securely and send that through? e.g. the tagging service can read all images but can also write the user's images with the location?

The problem is exacerbated if the user information is needed further downstream (2 or 3 microservices away). Do we just assume that it is up to individual microservices to restrict themselves to the actions that they need, and not make that explicit?

  • 1
    Are you the only developer of these microservices, or do other companies/organizations/departments (i.e. anything with a security boundary) also write microservices targeting your system? – Robert Harvey Oct 28 '17 at 16:31
  • 1
    It's very likely there'll be other services tarvetting the system, and we want to design for that case. – awr Oct 28 '17 at 23:02

In general, as many operations as possible should be tied to a real, human user. It forces people to authenticate properly, it pushes for a single consistent authorization strategy, and it's an important part of providing a cohesive audit trail.

And in general, you have three sort of scenarios with microservices:

1. The user comes in, uploads a photo, and it needs to be tagged. Great. The photo service can just pass along the JWT to the tagging service (or vice versa depending on the direction of your dependency) and if the user lacks rights to do the sub-operation you take the appropriate action (maybe upload the photo without a tag, maybe return the error, maybe something else).

2. The user comes in, uploads a photo, and it needs to be tagged... but not now. Cool. You handle the photo now as normal. Later, when the tagging occurs (event/message handling, CQRS style command processing, some periodic job processing, whatever) the tagging service will impersonate the user (most likely by using a shared secret to request a custom JWT from auth) and then do the sub-operation on behalf of the original requestor (with all of their permissions and limitations). This method has the usual problem with asynchronous operations where it's difficult to provide errors back to the user if things don't go smoothly, but if you're using this pattern for cross-service operations, you'd have already solved that.

3. Some sub-system needs to do stuff outside of the context of a user. Maybe you've got some nightly job to archive old images. Maybe your tags need to be consolidated... In this case, you probably do want each of these actors to have their own pseudo-user with limited permissions and a unique ID for the audit trail.

Which to use will vary depending on your scenario, your needs, and your risk tolerance. And of course, these are just an incomplete set of broad stroke generalizations.

But in general, microservices themselves should not be users if possible.

  • 1
    Aren't your first and last paragraphs contradictory? – Robert Harvey Oct 28 '17 at 17:41
  • 1
    No? Operations should be tied to a user. Microservices themselves aren’t users... I will clarify. – Telastyn Oct 28 '17 at 17:45
  • 1
    I came across a solution to the problem which suggested: define a scope for each microservice specifying which endpoints can be accessed, in its access token. Also pass the user's JWT id token as a different header. This way we can limit both microservices and users (defense in depth). Chapter 10 of manning.com/books/microservices-in-net-core – awr Oct 28 '17 at 22:56
  • Scenario 3 is an interesting one, which partly led us to deciding that users should be microservices. But looks like that can be an exception rather than the rule. – awr Oct 28 '17 at 23:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.